diff --git a/.github/workflows/aggregate-and-deploy-dashboard.yml b/.github/workflows/aggregate-and-deploy-dashboard.yml
new file mode 100644
index 00000000000..4e6989bda47
--- /dev/null
+++ b/.github/workflows/aggregate-and-deploy-dashboard.yml
@@ -0,0 +1,61 @@
+# Builds the CI dashboard static site from the committed JSON data file
+# and uploads the result as a downloadable Actions artifact.
+#
+# The aggregated_ci_results.json must be committed at:
+# ui/packages/ci-dashboard/public/data/aggregated_ci_results.json
+#
+# To view the dashboard locally after downloading:
+# 1. Download the artifact zip from the Actions run summary
+# 2. Unzip it
+# 3. python3 -m http.server 8080 (or: npx serve .)
+# 4. Open http://localhost:8080
+
+name: Deploy CI Dashboard
+
+on:
+ workflow_dispatch:
+
+ push:
+ branches: [main]
+ paths:
+ - 'ui/packages/ci-dashboard/src/**'
+ - 'ui/packages/ci-dashboard/index.html'
+ - 'ui/packages/ci-dashboard/public/data/aggregated_ci_results.json'
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '24'
+
+ - name: Set up pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: '10'
+
+ - name: Install dependencies
+ working-directory: ui/packages/ci-dashboard
+ run: pnpm install --frozen-lockfile
+
+ - name: Build dashboard
+ working-directory: ui/packages/ci-dashboard
+ run: pnpm build
+
+ - name: Upload dashboard artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ci-dashboard
+ path: ui/packages/ci-dashboard/dist
+ retention-days: 30
+
+
diff --git a/.github/workflows/update-dashboard-data.yml b/.github/workflows/update-dashboard-data.yml
new file mode 100644
index 00000000000..db57067f9e5
--- /dev/null
+++ b/.github/workflows/update-dashboard-data.yml
@@ -0,0 +1,77 @@
+# Downloads a fresh aggregated_ci_results.json from a URL you provide,
+# commits it to main, builds the dashboard, and uploads it as a
+# downloadable Actions artifact — no external hosting required.
+#
+# How to use:
+# 1. Upload your JSON file anywhere publicly reachable
+# (GitHub Gist raw URL, S3 presigned URL, any direct download link)
+# 2. Go to Actions → "Update Dashboard Data & Deploy"
+# 3. Click "Run workflow", paste the URL, click Run
+# 4. Download the "ci-dashboard" artifact from the run summary
+# 5. Unzip → python3 -m http.server 8080 → open http://localhost:8080
+
+name: Update Dashboard Data & Deploy
+
+on:
+ workflow_dispatch:
+ inputs:
+ data_url:
+ description: 'Direct download URL for aggregated_ci_results.json'
+ required: true
+
+permissions:
+ contents: write # needed to commit the JSON back to main
+
+jobs:
+ update-and-build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ ref: main
+
+ - name: Download data file
+ run: |
+ curl -fsSL "${{ inputs.data_url }}" \
+ -o ui/packages/ci-dashboard/public/data/aggregated_ci_results.json
+ # Basic sanity check — must be valid JSON
+ node -e "JSON.parse(require('fs').readFileSync(
+ 'ui/packages/ci-dashboard/public/data/aggregated_ci_results.json','utf8'
+ )); console.log('JSON valid')"
+
+ - name: Commit updated data to main
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git add ui/packages/ci-dashboard/public/data/aggregated_ci_results.json
+ git diff --cached --quiet || \
+ git commit -m "chore: update CI dashboard data [skip ci]"
+ git push origin main
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '24'
+
+ - name: Set up pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: '10'
+
+ - name: Install dependencies
+ working-directory: ui/packages/ci-dashboard
+ run: pnpm install --frozen-lockfile
+
+ - name: Build dashboard
+ working-directory: ui/packages/ci-dashboard
+ run: pnpm build
+
+ - name: Upload dashboard artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ci-dashboard
+ path: ui/packages/ci-dashboard/dist
+ retention-days: 30
+
diff --git a/.gitignore b/.gitignore
index 2282c5a8a1e..c1be6d033e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,3 +70,6 @@ terraform.rc
consul-k8s/
.vercel
vendor/
+
+# Leftover output from the Python CI aggregation script — not part of source
+/rc_aggregated_results.json
diff --git a/ui/packages/ci-dashboard/.gitignore b/ui/packages/ci-dashboard/.gitignore
new file mode 100644
index 00000000000..af49be68643
--- /dev/null
+++ b/ui/packages/ci-dashboard/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+dist/
+.DS_Store
+.vite/
+
+# Data files dropped here by CI – never commit real results to source control
+# public/data/*.json is intentionally committed — it is the dashboard data source.
diff --git a/ui/packages/ci-dashboard/README.md b/ui/packages/ci-dashboard/README.md
new file mode 100644
index 00000000000..cf9f051de83
--- /dev/null
+++ b/ui/packages/ci-dashboard/README.md
@@ -0,0 +1,305 @@
+# CI Dashboard
+
+A standalone, read-only dashboard that shows GitHub Actions workflow results
+for the Consul repository. It is built as a static site and deployed to
+GitHub Pages — completely separate from the Consul binary build.
+
+---
+
+## Architecture overview
+
+```
+GitHub Actions API
+ │
+ ▼
+scripts/aggregate.js ← fetches run + job data, writes JSON
+ │
+ ▼
+public/data/rc_aggregated_results.json
+ │
+ ▼
+Vite build (src/) ← pure JS + CSS, no framework
+ │
+ ▼
+dist/ ← static HTML/JS/CSS bundle
+ │
+ ▼
+GitHub Pages ← publicly accessible, no binary involved
+```
+
+All four stages happen inside a single GitHub Actions workflow
+(`.github/workflows/aggregate-and-deploy-dashboard.yml`). No external
+services, no secrets beyond the built-in `GITHUB_TOKEN`, no dependency on
+the main Consul binary build.
+
+---
+
+## Local development
+
+### Prerequisites
+
+| Tool | Version |
+|------|---------|
+| Node | ≥ 18 (built-in `fetch` required) |
+| pnpm | ≥ 10 |
+| GitHub personal access token | `repo` or `public_repo` read scope |
+
+### Steps
+
+```sh
+# 1. Install dashboard dependencies (from the monorepo root or this folder)
+cd ui/packages/ci-dashboard
+pnpm install
+
+# 2. Export your GitHub token
+export GITHUB_TOKEN=ghp_yourPersonalAccessToken
+
+# 3. Fetch workflow data for a branch and write the JSON
+node scripts/aggregate.js \
+ --repo hashicorp/consul \
+ --branch main \
+ --label "nightly-main" \
+ --output public/data/rc_aggregated_results.json
+
+# 4. Start the dev server
+pnpm dev
+# → http://localhost:5173
+```
+
+The `pnpm dev` server hot-reloads on source changes.
+The JSON file is served as a static asset from `public/data/` — re-run
+`aggregate.js` any time to pull fresher data.
+
+### Fetching multiple branches at once
+
+Each call to `aggregate.js` with `--existing` appends or updates a single
+entry in the output array. Run it once per branch; the dashboard's run
+selector will show all of them automatically.
+
+```sh
+OUTPUT="public/data/rc_aggregated_results.json"
+
+for branch in main release/1.20.x v2.0.0-rc3; do
+ node scripts/aggregate.js \
+ --repo hashicorp/consul \
+ --branch "$branch" \
+ --output "$OUTPUT" \
+ --existing "$OUTPUT"
+done
+
+pnpm dev
+```
+
+### Script flags reference
+
+| Flag | Required | Default | Description |
+|------|----------|---------|-------------|
+| `--repo` | Yes | — | `owner/repo`, e.g. `hashicorp/consul` |
+| `--branch` | Yes | — | Branch name or tag |
+| `--label` | No | branch name | Human-readable run label shown in the dashboard |
+| `--release-branch` | No | branch name | High-level branch label (e.g. `v2.0` for `v2.0.0-rc1`) |
+| `--release-version` | No | branch name | Version string shown in the run selector |
+| `--output` | No | `public/data/rc_aggregated_results.json` | Output path |
+| `--existing` | No | _(empty)_ | Path to existing JSON to append/update rather than overwrite |
+| `--max-runs` | No | `50` | Max workflow runs to fetch per branch (1–100) |
+| `--skip-annotations` | No | `false` | Skip check-run annotation fetching (faster, no test-level failure detail) |
+
+---
+
+## Production deployment
+
+### How it works
+
+One workflow file handles the full pipeline end-to-end:
+
+```
+.github/workflows/aggregate-and-deploy-dashboard.yml
+```
+
+```
+Trigger → checkout → pnpm install → aggregate.js (per branch) → vite build → GitHub Pages
+```
+
+No second workflow is needed. The earlier `deploy-ci-dashboard.yml` was
+removed because both files shared the same `concurrency: group: pages` key
+and would have deadlocked each other.
+
+### Trigger modes
+
+| Trigger | When it fires | Branches aggregated |
+|---------|--------------|---------------------|
+| `workflow_dispatch` | Manually from the Actions UI | Whatever you type in the input |
+| `schedule` (nightly 06:00 UTC) | Automatically every night | `main` |
+| `push` to `main` (source change) | When dashboard source files change | `main` |
+
+### Manual dispatch inputs
+
+Navigate to **Actions → Aggregate CI Data & Deploy Dashboard → Run workflow**:
+
+| Input | Example | Notes |
+|-------|---------|-------|
+| `branches` | `main,release/1.20.x,v2.0.0-rc3` | Comma-separated. Each branch becomes one entry in the run selector. |
+| `release_version_prefix` | `nightly` | Produces labels like `nightly-main`. Leave blank to use the branch name directly. |
+| `max_runs` | `30` | Higher = more history fetched but slower. Max 100. |
+
+### Permissions
+
+The workflow uses **only** the built-in `secrets.GITHUB_TOKEN`. No PAT or
+extra secrets are required. The token is granted these exact permissions:
+
+```yaml
+permissions:
+ contents: read # checkout the source
+ pages: write # deploy to GitHub Pages
+ id-token: write # OIDC token for Pages authentication
+ actions: read # read workflow run + job data via the API
+```
+
+The token is never written into any build artifact or the deployed JSON.
+
+---
+
+## Data flow and security
+
+### What the JSON contains
+
+The `rc_aggregated_results.json` file (and thus the deployed dashboard) contains:
+
+- Job names and workflow names
+- Statuses (`passed` / `failed` / `skipped`)
+- Pass rates and counts
+- Commit SHAs (first 12 characters shown in the UI, full SHA in the file)
+- Timestamps
+
+It does **not** contain:
+
+- The `GITHUB_TOKEN` or any other secret
+- Internal hostnames, IPs, or environment variables from runner environments
+- Log output or stdout from jobs
+- User data, PII, or access control information
+
+### Access control on the deployed site
+
+GitHub Pages supports restricting access to organisation members only.
+Enable this under repo **Settings → Pages → Access control**.
+
+---
+
+## Project structure
+
+```
+ui/packages/ci-dashboard/
+├── package.json # @consul/ci-dashboard — standalone, type: module
+├── vite.config.js # base: './' so dist/ is path-agnostic
+├── index.html
+├── .gitignore # ignores dist/, public/data/*.json
+│
+├── scripts/
+│ └── aggregate.js # Node 18+ script — fetches API data, writes JSON
+│
+├── public/
+│ └── data/
+│ └── .gitkeep # directory tracked; JSON files gitignored
+│
+└── src/
+ ├── main.js # state + render loop
+ ├── app.css # design tokens + full stylesheet
+ ├── utils/
+ │ └── format.js # escapeHtml, statusBadge, typeBadge, formatTimestamp
+ └── components/
+ ├── header.js # sticky dark header — repo/branch/run/commit chips
+ ├── summary-bar.js # SVG donut + 5 stat cards
+ ├── filters.js # type + status pill filters
+ └── job-table.js # sortable table with expandable test sub-rows
+```
+
+---
+
+## Adding a new branch permanently
+
+To have a branch always appear in the nightly schedule, edit the workflow:
+
+```yaml
+# aggregate-and-deploy-dashboard.yml — "Resolve branch list" step
+if [[ "${{ github.event_name }}" == "schedule" ... ]]; then
+ echo "branches=main,release/1.20.x" # ← add your branch here
+```
+
+---
+
+## Extending the type classifier
+
+Job type classification lives in `scripts/aggregate.js` in the
+`classifyJobType()` function. Add keywords to match your workflow naming:
+
+```js
+function classifyJobType(workflowName = '', jobName = '') {
+ const combined = `${workflowName} ${jobName}`.toLowerCase();
+
+ if (/\blint\b/.test(combined)) return 'Lint';
+ if (/\bui\b|\bfrontend\b|\bember\b|\bplaywright\b/.test(combined)) return 'UI';
+ if (/integrat|envoy|nomad|vault|consul-container|deployer/.test(combined)) return 'Integration';
+ return 'Other';
+}
+```
+
+---
+
+## Test-level failure detail (check-run annotations)
+
+When the aggregation script runs it automatically fetches **check-run annotations**
+for every failed job. This surfaces individual test names, failure messages,
+and file:line locations without any changes to your existing workflows.
+
+### How it works
+
+GitHub Actions converts `::error file=…,line=…::message` commands written to
+stdout into structured check-run annotations. The Consul Go test suite already
+emits these via:
+
+```yaml
+go run gotest.tools/gotestsum@v… \
+ --format=github-actions \ # ← writes ::error:: annotations
+ --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- …
+```
+
+The script calls `GET /repos/{owner}/{repo}/check-runs/{id}/annotations`
+for each failed job and stores the results in `job.annotations[]`.
+
+### What you see in the dashboard
+
+When a failed job is clicked:
+- **Annotation panel** — shown when check-run failures were captured.
+ Displays test name, file:line link to the exact line on GitHub, and a
+ collapsible failure detail block with the full `gotestsum` output.
+- **Steps panel** — shown as a fallback when no annotation data is
+ available (non-test jobs, lint, build steps).
+- **No breakdown** — shown when neither situation applies (e.g., network
+ error during aggregation).
+
+The summary bar's fifth card also switches from "Cases" to **"Test Failures"**
+(shown in red) when annotation data is present.
+
+### Skipping annotation fetching
+
+Pass `--skip-annotations` to omit the extra API calls. Useful during
+development or if you have very many failed jobs:
+
+```bash
+node scripts/aggregate.js \
+ --repo hashicorp/consul \
+ --branch main \
+ --skip-annotations
+```
+
+### Full JUnit XML (optional enrichment)
+
+Check-run annotations only capture *failures*. For a full pass/fail/skip
+breakdown per test (not just failed ones), upload and parse the JUnit XML
+that `gotestsum` already writes. The `reusable-unit.yml` workflow uploads
+it as `{RANDOM_ID}-test-results/gotestsum-report.xml`.
+
+To enable richer data, add a download + extract step in the GitHub Actions
+workflow before calling `aggregate.js`, then pass a `--junit-dir` path
+(a planned future flag). This is not required for the current feature set.
+
diff --git a/ui/packages/ci-dashboard/index.html b/ui/packages/ci-dashboard/index.html
new file mode 100644
index 00000000000..374dc5a4131
--- /dev/null
+++ b/ui/packages/ci-dashboard/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+ Consul CI Dashboard
+
+
+
+
+
+
diff --git a/ui/packages/ci-dashboard/package.json b/ui/packages/ci-dashboard/package.json
new file mode 100644
index 00000000000..f172dcb1cf9
--- /dev/null
+++ b/ui/packages/ci-dashboard/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "@consul/ci-dashboard",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "description": "Read-only CI workflow results dashboard for Consul. Not shipped with the Consul binary.",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "aggregate": "node scripts/aggregate.js"
+ },
+ "devDependencies": {
+ "vite": "^5.4.0"
+ }
+}
diff --git a/ui/packages/ci-dashboard/public/data/.gitkeep b/ui/packages/ci-dashboard/public/data/.gitkeep
new file mode 100644
index 00000000000..3a00d8229d0
--- /dev/null
+++ b/ui/packages/ci-dashboard/public/data/.gitkeep
@@ -0,0 +1,3 @@
+# CI drops aggregated_ci_results.json here at build time.
+# This directory is intentionally empty in source control.
+# See .gitignore — *.json files in this folder are excluded.
diff --git a/ui/packages/ci-dashboard/public/data/aggregated_ci_results.json b/ui/packages/ci-dashboard/public/data/aggregated_ci_results.json
new file mode 100644
index 00000000000..d48ef136a71
--- /dev/null
+++ b/ui/packages/ci-dashboard/public/data/aggregated_ci_results.json
@@ -0,0 +1,5748 @@
+[
+ {
+ "release_branch": "v2.0",
+ "release_version": "v2.0.0-rc1",
+ "repo": "hashicorp/consul",
+ "run_id": "Tag-v2.0.0-rc1",
+ "branch": "v2.0.0-rc1",
+ "commit_sha": "cf4eda6514e6f23a2a0dd82709a2d16ae1b6f917",
+ "timestamp": "2026-05-18T17:55:52.817701Z",
+ "summary": {
+ "total_jobs": 84,
+ "total_tests": 84,
+ "total_cases": 84,
+ "passed": 52,
+ "failed": 0,
+ "skipped": 32,
+ "duration_seconds": 0.0,
+ "pass_rate": 61.9
+ },
+ "jobs": [
+ {
+ "job_id": "promote-production",
+ "name": "promote-production",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "promote-production-test",
+ "name": "promote-production",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "promote-staging",
+ "name": "promote-staging",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "promote-staging-test",
+ "name": "promote-staging",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "prepare",
+ "name": "prepare",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "prepare-test",
+ "name": "prepare",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build",
+ "name": "build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-test",
+ "name": "build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-armhf-debian-package",
+ "name": "Verify armhf debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-armhf-debian-package-test",
+ "name": "Verify armhf debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-arm64-build",
+ "name": "Docker arm64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-arm64-build-test",
+ "name": "Docker arm64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-i386-debian-package",
+ "name": "Verify i386 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-i386-debian-package-test",
+ "name": "Verify i386 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-amd64-build",
+ "name": "Docker amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-amd64-build-test",
+ "name": "Docker amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-amd64-debian-package",
+ "name": "Verify amd64 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-amd64-debian-package-test",
+ "name": "Verify amd64 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm64-linux-binary",
+ "name": "Verify arm64 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm64-linux-binary-test",
+ "name": "Verify arm64 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm64-debian-package",
+ "name": "Verify arm64 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm64-debian-package-test",
+ "name": "Verify arm64 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-386-build",
+ "name": "Docker 386 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-386-build-test",
+ "name": "Docker 386 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-build-ubi-images",
+ "name": "Docker Build UBI Images",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-build-ubi-images-test",
+ "name": "Docker Build UBI Images",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-386-linux-binary",
+ "name": "Verify 386 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-386-linux-binary-test",
+ "name": "Verify 386 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-amd64-linux-binary",
+ "name": "Verify amd64 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-amd64-linux-binary-test",
+ "name": "Verify amd64 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-x86_64-rpm",
+ "name": "Verify x86_64 rpm",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-x86_64-rpm-test",
+ "name": "Verify x86_64 rpm",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm-linux-binary",
+ "name": "Verify arm linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm-linux-binary-test",
+ "name": "Verify arm linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-arm-build",
+ "name": "Docker arm build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-arm-build-test",
+ "name": "Docker arm build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-i386-rpm",
+ "name": "Verify i386 rpm",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-i386-rpm-test",
+ "name": "Verify i386 rpm",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-distros-success",
+ "name": "build-distros-success",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-distros-success-test",
+ "name": "build-distros-success",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-s390x",
+ "name": "build-s390x",
+ "type": "UI",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "build-s390x-test",
+ "name": "build-s390x",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-amd64",
+ "name": "build-amd64",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-amd64-test",
+ "name": "build-amd64",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-386",
+ "name": "build-386",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-386-test",
+ "name": "build-386",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-arm",
+ "name": "build-arm",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-arm-test",
+ "name": "build-arm",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "test-integrations-success",
+ "name": "test-integrations-success",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "test-integrations-success-test",
+ "name": "test-integrations-success",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test",
+ "name": "envoy-integration-test",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-test",
+ "name": "envoy-integration-test",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "nomad-integration-test",
+ "name": "nomad-integration-test",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "nomad-integration-test-test",
+ "name": "nomad-integration-test",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "integration-test-with-deployer",
+ "name": "integration-test-with-deployer",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "integration-test-with-deployer-test",
+ "name": "integration-test-with-deployer",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "setup",
+ "name": "Setup",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "setup-test",
+ "name": "Setup",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "vault-integration-test",
+ "name": "vault-integration-test",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "vault-integration-test-test",
+ "name": "vault-integration-test",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "dev-build",
+ "name": "dev-build",
+ "type": "UI",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "dev-build-test",
+ "name": "dev-build",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "generate-envoy-job-matrices",
+ "name": "Generate Envoy Job Matrices",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "generate-envoy-job-matrices-test",
+ "name": "Generate Envoy Job Matrices",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-tests-success",
+ "name": "go-tests-success",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-tests-success-test",
+ "name": "go-tests-success",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce",
+ "name": "go-test-ce",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-test",
+ "name": "go-test-ce",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-testing-deployer",
+ "name": "go-test-testing-deployer",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-testing-deployer-test",
+ "name": "go-test-testing-deployer",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-race",
+ "name": "go-test-race",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-race-test",
+ "name": "go-test-race",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-api",
+ "name": "go-test-api",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-api-test",
+ "name": "go-test-api",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-troubleshoot",
+ "name": "go-test-troubleshoot",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-troubleshoot-test",
+ "name": "go-test-troubleshoot",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-codegen",
+ "name": "check-codegen",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "check-codegen-test",
+ "name": "check-codegen",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-consul-retry",
+ "name": "lint-consul-retry",
+ "type": "Lint",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "lint-consul-retry-test",
+ "name": "lint-consul-retry",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-envoyextensions",
+ "name": "go-test-envoyextensions",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-envoyextensions-test",
+ "name": "go-test-envoyextensions",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-enterprise",
+ "name": "go-test-enterprise",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-enterprise-test",
+ "name": "go-test-enterprise",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-32bit",
+ "name": "go-test-32bit",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-32bit-test",
+ "name": "go-test-32bit",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-sdk-1.25",
+ "name": "go-test-sdk-1.25",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-sdk-1.25-test",
+ "name": "go-test-sdk-1.25",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-api-1.25",
+ "name": "go-test-api-1.25",
+ "type": "Integration",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-api-1.25-test",
+ "name": "go-test-api-1.25",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit",
+ "name": "lint-32bit",
+ "type": "Lint",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-test",
+ "name": "lint-32bit",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-generated-protobuf",
+ "name": "check-generated-protobuf",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "check-generated-protobuf-test",
+ "name": "check-generated-protobuf",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-sdk",
+ "name": "go-test-sdk",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-sdk-test",
+ "name": "go-test-sdk",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-container-test-deps",
+ "name": "lint-container-test-deps",
+ "type": "Lint",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "lint-container-test-deps-test",
+ "name": "lint-container-test-deps",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "dev-build",
+ "name": "dev-build",
+ "type": "UI",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "dev-build-test",
+ "name": "dev-build",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-enums",
+ "name": "lint-enums",
+ "type": "Lint",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "lint-enums-test",
+ "name": "lint-enums",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "setup",
+ "name": "Setup",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "setup-test",
+ "name": "Setup",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint",
+ "name": "lint",
+ "type": "Lint",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "lint-test",
+ "name": "lint",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-go-mod",
+ "name": "check-go-mod",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "check-go-mod-test",
+ "name": "check-go-mod",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-${{-needs.get-go-version.outputs.go-version-}}-${{-matrix.goos-}}-${{-matrix.goarch-}}-build",
+ "name": "Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build",
+ "type": "UI",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-${{-needs.get-go-version.outputs.go-version-}}-${{-matrix.goos-}}-${{-matrix.goarch-}}-build-test",
+ "name": "Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-windows-amd64-build",
+ "name": "Go 1.26.2 windows amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-windows-amd64-build-test",
+ "name": "Go 1.26.2 windows amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-freebsd-amd64-build",
+ "name": "Go 1.26.2 freebsd amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-freebsd-amd64-build-test",
+ "name": "Go 1.26.2 freebsd amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-freebsd-386-build",
+ "name": "Go 1.26.2 freebsd 386 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-freebsd-386-build-test",
+ "name": "Go 1.26.2 freebsd 386 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-solaris-amd64-build",
+ "name": "Go 1.26.2 solaris amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-solaris-amd64-build-test",
+ "name": "Go 1.26.2 solaris amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-linux-amd64-build",
+ "name": "Go 1.26.2 linux amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-linux-amd64-build-test",
+ "name": "Go 1.26.2 linux amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-windows-386-build",
+ "name": "Go 1.26.2 windows 386 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-windows-386-build-test",
+ "name": "Go 1.26.2 windows 386 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-linux-arm64-build",
+ "name": "Go 1.26.2 linux arm64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-linux-arm64-build-test",
+ "name": "Go 1.26.2 linux arm64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-darwin-arm64-build",
+ "name": "Go 1.26.2 darwin arm64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-darwin-arm64-build-test",
+ "name": "Go 1.26.2 darwin arm64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-darwin-amd64-build",
+ "name": "Go 1.26.2 darwin amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-darwin-amd64-build-test",
+ "name": "Go 1.26.2 darwin amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-linux-arm-build",
+ "name": "Go 1.26.2 linux arm build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-linux-arm-build-test",
+ "name": "Go 1.26.2 linux arm build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-1.26.2-linux-386-build",
+ "name": "Go 1.26.2 linux 386 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-1.26.2-linux-386-build-test",
+ "name": "Go 1.26.2 linux 386 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "validate-outputs",
+ "name": "validate-outputs",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "validate-outputs-test",
+ "name": "validate-outputs",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "generate-metadata-file",
+ "name": "generate-metadata-file",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "generate-metadata-file-test",
+ "name": "generate-metadata-file",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "scan",
+ "name": "scan",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "scan-test",
+ "name": "scan",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-go-mod-/-check-go-mod",
+ "name": "check-go-mod / check-go-mod",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "check-go-mod-/-check-go-mod-test",
+ "name": "check-go-mod / check-go-mod",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "conditional-skip-/-check-whether-to-skip-build-and-tests",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "conditional-skip-/-check-whether-to-skip-build-and-tests-test",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "noop",
+ "name": "noop",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "noop-test",
+ "name": "noop",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "conditional-skip-/-check-whether-to-skip-build-and-tests",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "conditional-skip-/-check-whether-to-skip-build-and-tests-test",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-envoy-versions-/-determine-supported-envoy-versions",
+ "name": "get-envoy-versions / Determine supported Envoy versions",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-envoy-versions-/-determine-supported-envoy-versions-test",
+ "name": "get-envoy-versions / Determine supported Envoy versions",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "setup",
+ "name": "Setup",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "setup-test",
+ "name": "Setup",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "setup",
+ "name": "Setup",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "setup-test",
+ "name": "Setup",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-ci-success",
+ "name": "verify-ci-success",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-ci-success-test",
+ "name": "verify-ci-success",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "set-product-version",
+ "name": "set-product-version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "set-product-version-test",
+ "name": "set-product-version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-envoy-version",
+ "name": "verify-envoy-version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-envoy-version-test",
+ "name": "verify-envoy-version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "release_branch": "v2.0",
+ "release_version": "v2.0.0-rc2",
+ "repo": "hashicorp/consul",
+ "run_id": "Tag-v2.0.0-rc2",
+ "branch": "v2.0.0-rc2",
+ "commit_sha": "c1dcea03739013e2619e980484c02945b81a19bc",
+ "timestamp": "2026-05-18T17:55:55.580760Z",
+ "summary": {
+ "total_jobs": 100,
+ "total_tests": 100,
+ "total_cases": 100,
+ "passed": 99,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0.0,
+ "pass_rate": 99.0
+ },
+ "jobs": [
+ {
+ "job_id": "promote-production",
+ "name": "promote-production",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "promote-production-test",
+ "name": "promote-production",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "promote-staging",
+ "name": "promote-staging",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "promote-staging-test",
+ "name": "promote-staging",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-tests-success",
+ "name": "go-tests-success",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-tests-success-test",
+ "name": "go-tests-success",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build-distros-success",
+ "name": "build-distros-success",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-distros-success-test",
+ "name": "build-distros-success",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "conditional-skip-/-check-whether-to-skip-build-and-tests",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "conditional-skip-/-check-whether-to-skip-build-and-tests-test",
+ "name": "conditional-skip / Check whether to skip build and tests",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "noop",
+ "name": "noop",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "noop-test",
+ "name": "noop",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/agent)",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/agent)",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/agent)-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/agent)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-test-integ",
+ "name": "lint / lint test-integ",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-test-integ-test",
+ "name": "lint / lint test-integ",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-testing/deployer",
+ "name": "lint-32bit / lint testing/deployer",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-testing/deployer-test",
+ "name": "lint-32bit / lint testing/deployer",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/event,-github.com/hashicorp/consul/command/kv/imp,-g...",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/event, github.com/hashicorp/consul/command/kv/imp, g...",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/event,-github.com/hashicorp/consul/command/kv/imp,-g...-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/event, github.com/hashicorp/consul/command/kv/imp, g...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/services/register,-github.com/hashicorp/consul/ipadd...",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/services/register, github.com/hashicorp/consul/ipadd...",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/services/register,-github.com/hashicorp/consul/ipadd...-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/services/register, github.com/hashicorp/consul/ipadd...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/tls,-github.com/hashicorp/consul/agent/consul/stream...",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/tls, github.com/hashicorp/consul/agent/consul/stream...",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/tls,-github.com/hashicorp/consul/agent/consul/stream...-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/tls, github.com/hashicorp/consul/agent/consul/stream...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-testing/deployer",
+ "name": "lint / lint testing/deployer",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-testing/deployer-test",
+ "name": "lint / lint testing/deployer",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/lib/template,-github.com/hashicorp/consul/command/acl/token/...",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/lib/template, github.com/hashicorp/consul/command/acl/token/...",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/lib/template,-github.com/hashicorp/consul/command/acl/token/...-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/lib/template, github.com/hashicorp/consul/command/acl/token/...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/logout,-github.com/hashicorp/consul/command/snapshot...",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/logout, github.com/hashicorp/consul/command/snapshot...",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-go-test-(github.com/hashicorp/consul/command/logout,-github.com/hashicorp/consul/command/snapshot...-test",
+ "name": "go-test-ce / go-test (github.com/hashicorp/consul/command/logout, github.com/hashicorp/consul/command/snapshot...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-envoyextensions",
+ "name": "lint-32bit / lint envoyextensions",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-envoyextensions-test",
+ "name": "lint-32bit / lint envoyextensions",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-sdk-1.25-/-go-test",
+ "name": "go-test-sdk-1.25 / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-sdk-1.25-/-go-test-test",
+ "name": "go-test-sdk-1.25 / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-race-/-go-test",
+ "name": "go-test-race / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-race-/-go-test-test",
+ "name": "go-test-race / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-testing-deployer-/-go-test",
+ "name": "go-test-testing-deployer / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-testing-deployer-/-go-test-test",
+ "name": "go-test-testing-deployer / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-test/integration/consul-container",
+ "name": "lint / lint test/integration/consul-container",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-test/integration/consul-container-test",
+ "name": "lint / lint test/integration/consul-container",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-troubleshoot",
+ "name": "lint-32bit / lint troubleshoot",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-troubleshoot-test",
+ "name": "lint-32bit / lint troubleshoot",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-test-integ",
+ "name": "lint-32bit / lint test-integ",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-test-integ-test",
+ "name": "lint-32bit / lint test-integ",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-sdk-/-go-test",
+ "name": "go-test-sdk / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-sdk-/-go-test-test",
+ "name": "go-test-sdk / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-envoyextensions-/-go-test",
+ "name": "go-test-envoyextensions / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-envoyextensions-/-go-test-test",
+ "name": "go-test-envoyextensions / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-api-/-go-test",
+ "name": "go-test-api / go-test",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-api-/-go-test-test",
+ "name": "go-test-api / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-ce-/-set-test-package-matrix",
+ "name": "go-test-ce / set-test-package-matrix",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-ce-/-set-test-package-matrix-test",
+ "name": "go-test-ce / set-test-package-matrix",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-troubleshoot",
+ "name": "lint / lint troubleshoot",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-troubleshoot-test",
+ "name": "lint / lint troubleshoot",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-api-1.25-/-go-test",
+ "name": "go-test-api-1.25 / go-test",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-api-1.25-/-go-test-test",
+ "name": "go-test-api-1.25 / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-envoyextensions",
+ "name": "lint / lint envoyextensions",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-envoyextensions-test",
+ "name": "lint / lint envoyextensions",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-test/integration/consul-container",
+ "name": "lint-32bit / lint test/integration/consul-container",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-test/integration/consul-container-test",
+ "name": "lint-32bit / lint test/integration/consul-container",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-troubleshoot-/-go-test",
+ "name": "go-test-troubleshoot / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-troubleshoot-/-go-test-test",
+ "name": "go-test-troubleshoot / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-32bit-/-go-test",
+ "name": "go-test-32bit / go-test",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "go-test-32bit-/-go-test-test",
+ "name": "go-test-32bit / go-test",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "go-test-enterprise",
+ "name": "go-test-enterprise",
+ "type": "Other",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "tests": [
+ {
+ "test_id": "go-test-enterprise-test",
+ "name": "go-test-enterprise",
+ "package": "hashicorp/consul",
+ "status": "skipped",
+ "stats": {
+ "total": 1,
+ "passed": 0,
+ "failed": 0,
+ "skipped": 1,
+ "duration_seconds": 0,
+ "pass_rate": 0
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-codegen",
+ "name": "check-codegen",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "check-codegen-test",
+ "name": "check-codegen",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "dev-build-/-build",
+ "name": "dev-build / build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "dev-build-/-build-test",
+ "name": "dev-build / build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint",
+ "name": "lint / lint",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-test",
+ "name": "lint / lint",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-api",
+ "name": "lint-32bit / lint api",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-api-test",
+ "name": "lint-32bit / lint api",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-sdk",
+ "name": "lint / lint sdk",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-sdk-test",
+ "name": "lint / lint sdk",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-generated-protobuf",
+ "name": "check-generated-protobuf",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "check-generated-protobuf-test",
+ "name": "check-generated-protobuf",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint-sdk",
+ "name": "lint-32bit / lint sdk",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-sdk-test",
+ "name": "lint-32bit / lint sdk",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-container-test-deps",
+ "name": "lint-container-test-deps",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-container-test-deps-test",
+ "name": "lint-container-test-deps",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "setup",
+ "name": "Setup",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "setup-test",
+ "name": "Setup",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-/-lint-api",
+ "name": "lint / lint api",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-/-lint-api-test",
+ "name": "lint / lint api",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-32bit-/-lint",
+ "name": "lint-32bit / lint",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-32bit-/-lint-test",
+ "name": "lint-32bit / lint",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-enums",
+ "name": "lint-enums",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-enums-test",
+ "name": "lint-enums",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "check-go-mod-/-check-go-mod",
+ "name": "check-go-mod / check-go-mod",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "check-go-mod-/-check-go-mod-test",
+ "name": "check-go-mod / check-go-mod",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "lint-consul-retry",
+ "name": "lint-consul-retry",
+ "type": "Lint",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "lint-consul-retry-test",
+ "name": "lint-consul-retry",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "get-go-version-/-determine-go-toolchain-version",
+ "name": "get-go-version / Determine Go toolchain version",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "get-go-version-/-determine-go-toolchain-version-test",
+ "name": "get-go-version / Determine Go toolchain version",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "test-integrations-success",
+ "name": "test-integrations-success",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "test-integrations-success-test",
+ "name": "test-integrations-success",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "prepare",
+ "name": "prepare",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "prepare-test",
+ "name": "prepare",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "build",
+ "name": "build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "build-test",
+ "name": "build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm64-linux-binary",
+ "name": "Verify arm64 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm64-linux-binary-test",
+ "name": "Verify arm64 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-i386-debian-package",
+ "name": "Verify i386 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-i386-debian-package-test",
+ "name": "Verify i386 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-amd64-linux-binary",
+ "name": "Verify amd64 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-amd64-linux-binary-test",
+ "name": "Verify amd64 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-amd64-debian-package",
+ "name": "Verify amd64 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-amd64-debian-package-test",
+ "name": "Verify amd64 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm64-debian-package",
+ "name": "Verify arm64 debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm64-debian-package-test",
+ "name": "Verify arm64 debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-arm-build",
+ "name": "Docker arm build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-arm-build-test",
+ "name": "Docker arm build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-386-build",
+ "name": "Docker 386 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-386-build-test",
+ "name": "Docker 386 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-amd64-build",
+ "name": "Docker amd64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-amd64-build-test",
+ "name": "Docker amd64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-386-linux-binary",
+ "name": "Verify 386 linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-386-linux-binary-test",
+ "name": "Verify 386 linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-armhf-debian-package",
+ "name": "Verify armhf debian package",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-armhf-debian-package-test",
+ "name": "Verify armhf debian package",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-arm64-build",
+ "name": "Docker arm64 build",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-arm64-build-test",
+ "name": "Docker arm64 build",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-i386-rpm",
+ "name": "Verify i386 rpm",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-i386-rpm-test",
+ "name": "Verify i386 rpm",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-x86_64-rpm",
+ "name": "Verify x86_64 rpm",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-x86_64-rpm-test",
+ "name": "Verify x86_64 rpm",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "verify-arm-linux-binary",
+ "name": "Verify arm linux binary",
+ "type": "Other",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "verify-arm-linux-binary-test",
+ "name": "Verify arm linux binary",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "docker-build-ubi-images",
+ "name": "Docker Build UBI Images",
+ "type": "UI",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "docker-build-ubi-images-test",
+ "name": "Docker Build UBI Images",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.36.6,-case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "name": "envoy-integration-test (client, 1.36.6, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.36.6,-case-terminating-gateway-subsets|case-ingress-gateway-sds...-test",
+ "name": "envoy-integration-test (client, 1.36.6, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.34.14,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "name": "envoy-integration-test (client, 1.34.14, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.34.14,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...-test",
+ "name": "envoy-integration-test (client, 1.34.14, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.35.10,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "name": "envoy-integration-test (client, 1.35.10, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.35.10,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...-test",
+ "name": "envoy-integration-test (client, 1.35.10, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.35.10,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "name": "envoy-integration-test (client, 1.35.10, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.35.10,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...-test",
+ "name": "envoy-integration-test (client, 1.35.10, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.35.10,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (client, 1.35.10, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.35.10,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (client, 1.35.10, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.34.14,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (client, 1.34.14, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.34.14,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (client, 1.34.14, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.35.10,-case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "name": "envoy-integration-test (client, 1.35.10, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.35.10,-case-terminating-gateway-subsets|case-ingress-gateway-sd...-test",
+ "name": "envoy-integration-test (client, 1.35.10, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.34.14,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (server, 1.34.14, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.34.14,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (server, 1.34.14, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.34.14,-case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "name": "envoy-integration-test (server, 1.34.14, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.34.14,-case-terminating-gateway-subsets|case-ingress-gateway-sd...-test",
+ "name": "envoy-integration-test (server, 1.34.14, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.34.14,-case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "name": "envoy-integration-test (client, 1.34.14, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.34.14,-case-terminating-gateway-subsets|case-ingress-gateway-sd...-test",
+ "name": "envoy-integration-test (client, 1.34.14, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.37.2,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (client, 1.37.2, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.37.2,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (client, 1.37.2, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.34.14,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "name": "envoy-integration-test (client, 1.34.14, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.34.14,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...-test",
+ "name": "envoy-integration-test (client, 1.34.14, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.37.2,-case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "name": "envoy-integration-test (client, 1.37.2, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.37.2,-case-terminating-gateway-subsets|case-ingress-gateway-sds...-test",
+ "name": "envoy-integration-test (client, 1.37.2, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.36.6,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "name": "envoy-integration-test (client, 1.36.6, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.36.6,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...-test",
+ "name": "envoy-integration-test (client, 1.36.6, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.37.2,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "name": "envoy-integration-test (client, 1.37.2, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.37.2,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...-test",
+ "name": "envoy-integration-test (client, 1.37.2, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.36.6,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "name": "envoy-integration-test (client, 1.36.6, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.36.6,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...-test",
+ "name": "envoy-integration-test (client, 1.36.6, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.37.2,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "name": "envoy-integration-test (client, 1.37.2, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.37.2,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...-test",
+ "name": "envoy-integration-test (client, 1.37.2, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.34.14,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "name": "envoy-integration-test (server, 1.34.14, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.34.14,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...-test",
+ "name": "envoy-integration-test (server, 1.34.14, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.34.14,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "name": "envoy-integration-test (server, 1.34.14, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.34.14,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...-test",
+ "name": "envoy-integration-test (server, 1.34.14, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(client,-1.36.6,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (client, 1.36.6, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(client,-1.36.6,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (client, 1.36.6, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.36.6,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "name": "envoy-integration-test (server, 1.36.6, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.36.6,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...-test",
+ "name": "envoy-integration-test (server, 1.36.6, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.36.6,-case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "name": "envoy-integration-test (server, 1.36.6, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.36.6,-case-terminating-gateway-subsets|case-ingress-gateway-sds...-test",
+ "name": "envoy-integration-test (server, 1.36.6, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.35.10,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (server, 1.35.10, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.35.10,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (server, 1.35.10, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.36.6,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (server, 1.36.6, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.36.6,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (server, 1.36.6, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.37.2,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "name": "envoy-integration-test (server, 1.37.2, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.37.2,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...-test",
+ "name": "envoy-integration-test (server, 1.37.2, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.35.10,-case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "name": "envoy-integration-test (server, 1.35.10, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.35.10,-case-terminating-gateway-subsets|case-ingress-gateway-sd...-test",
+ "name": "envoy-integration-test (server, 1.35.10, case-terminating-gateway-subsets|case-ingress-gateway-sd...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.36.6,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "name": "envoy-integration-test (server, 1.36.6, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.36.6,-case-cfg-resolver-dc-failover-gateways-remote|case-ingres...-test",
+ "name": "envoy-integration-test (server, 1.36.6, case-cfg-resolver-dc-failover-gateways-remote|case-ingres...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.37.2,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "name": "envoy-integration-test (server, 1.37.2, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.37.2,-docs|case-cfg-resolver-features|case-cfg-splitter-cluster...-test",
+ "name": "envoy-integration-test (server, 1.37.2, docs|case-cfg-resolver-features|case-cfg-splitter-cluster...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.35.10,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "name": "envoy-integration-test (server, 1.35.10, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.35.10,-case-cfg-resolver-dc-failover-gateways-remote|case-ingre...-test",
+ "name": "envoy-integration-test (server, 1.35.10, case-cfg-resolver-dc-failover-gateways-remote|case-ingre...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.37.2,-case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "name": "envoy-integration-test (server, 1.37.2, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.37.2,-case-terminating-gateway-subsets|case-ingress-gateway-sds...-test",
+ "name": "envoy-integration-test (server, 1.37.2, case-terminating-gateway-subsets|case-ingress-gateway-sds...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.35.10,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "name": "envoy-integration-test (server, 1.35.10, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.35.10,-docs|case-cfg-resolver-features|case-cfg-splitter-cluste...-test",
+ "name": "envoy-integration-test (server, 1.35.10, docs|case-cfg-resolver-features|case-cfg-splitter-cluste...",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "envoy-integration-test-(server,-1.37.2,-case-wanfed-gw|case-mesh-to-lambda)",
+ "name": "envoy-integration-test (server, 1.37.2, case-wanfed-gw|case-mesh-to-lambda)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "envoy-integration-test-(server,-1.37.2,-case-wanfed-gw|case-mesh-to-lambda)-test",
+ "name": "envoy-integration-test (server, 1.37.2, case-wanfed-gw|case-mesh-to-lambda)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "vault-integration-test-(1.21.0)",
+ "name": "vault-integration-test (1.21.0)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "vault-integration-test-(1.21.0)-test",
+ "name": "vault-integration-test (1.21.0)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ },
+ {
+ "job_id": "vault-integration-test-(1.19.2)",
+ "name": "vault-integration-test (1.19.2)",
+ "type": "Integration",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "tests": [
+ {
+ "test_id": "vault-integration-test-(1.19.2)-test",
+ "name": "vault-integration-test (1.19.2)",
+ "package": "hashicorp/consul",
+ "status": "passed",
+ "stats": {
+ "total": 1,
+ "passed": 1,
+ "failed": 0,
+ "skipped": 0,
+ "duration_seconds": 0,
+ "pass_rate": 100
+ },
+ "cases": []
+ }
+ ]
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/ui/packages/ci-dashboard/scripts/aggregate.js b/ui/packages/ci-dashboard/scripts/aggregate.js
new file mode 100644
index 00000000000..cf07fa11824
--- /dev/null
+++ b/ui/packages/ci-dashboard/scripts/aggregate.js
@@ -0,0 +1,772 @@
+#!/usr/bin/env node
+// Copyright IBM Corp. 2024, 2026
+// SPDX-License-Identifier: BUSL-1.1
+//
+// aggregate.js — Fetch GitHub Actions workflow run data and produce the
+// aggregated_ci_results.json consumed by the CI dashboard.
+//
+// Two modes:
+//
+// Branch mode (default) — fetches workflow runs for a branch:
+// node scripts/aggregate.js \
+// --repo hashicorp/consul \
+// --branch main \
+// --label "nightly-main" \
+// --release-branch main \
+// --release-version "main-$(date +%Y%m%d)" \
+// --output public/data/aggregated_ci_results.json
+//
+// Tag mode (RC releases) — fetches check-runs by RC tag commit SHA:
+// node scripts/aggregate.js \
+// --repo hashicorp/consul \
+// --tag-pattern v2.0 \
+// --output public/data/aggregated_ci_results.json
+//
+// Environment:
+// GITHUB_TOKEN — a token with `repo` (or `public_repo`) read scope.
+// In GitHub Actions this is automatically available as
+// secrets.GITHUB_TOKEN; no extra secret needed.
+//
+// Security note:
+// The token is read from the environment and used only for API calls.
+// It is NEVER written into the output JSON. The output contains only
+// job names, statuses, pass rates, and commit SHAs — no credentials.
+//
+// No third-party dependencies. Requires Node ≥ 18 (built-in fetch).
+
+import { writeFileSync, readFileSync, mkdirSync } from 'node:fs';
+import { dirname, resolve } from 'node:path';
+import { parseArgs } from 'node:util';
+
+// ─── CLI args ─────────────────────────────────────────────────────────────
+const { values: args } = parseArgs({
+ options: {
+ repo: { type: 'string' },
+ branch: { type: 'string' },
+ label: { type: 'string' },
+ 'release-branch': { type: 'string' },
+ 'release-version': { type: 'string' },
+ output: { type: 'string', default: 'public/data/aggregated_ci_results.json' },
+ 'max-runs': { type: 'string', default: '50' }, // max workflow runs to fetch per page
+ 'existing': { type: 'string', default: '' }, // path to existing JSON to append to (optional)
+ 'skip-annotations': { type: 'boolean', default: false }, // skip check-run annotation fetching (faster but less detail)
+ 'tag-pattern': { type: 'string', default: '' }, // tag prefix for RC mode, e.g. "v2.0"
+ },
+ strict: true,
+ allowPositionals: false,
+});
+
+// In tag mode --branch is not required; in branch mode --branch IS required.
+const TAG_PATTERN = args['tag-pattern'];
+if (!args['repo']) {
+ console.error('Error: --repo is required.');
+ process.exit(1);
+}
+if (!TAG_PATTERN && !args['branch']) {
+ console.error('Error: either --branch or --tag-pattern is required.');
+ process.exit(1);
+}
+
+// ─── Token — read once, never log, clear the named binding after use ─────
+const _rawToken = process.env.GITHUB_TOKEN;
+if (!_rawToken) {
+ console.error('Error: GITHUB_TOKEN environment variable is not set.');
+ process.exit(1);
+}
+
+// Build auth headers immediately and drop the raw token reference so it
+// cannot be accidentally serialised or logged anywhere below this point.
+const _HEADERS = Object.freeze({
+ 'Authorization': `Bearer ${_rawToken}`,
+ 'Accept': 'application/vnd.github+json',
+ 'X-GitHub-Api-Version': '2022-11-28',
+ 'User-Agent': 'consul-ci-dashboard/1.0',
+});
+// Intentionally shadow the raw token to make the value inaccessible by name.
+const _rawToken_cleared = undefined; // eslint-disable-line no-unused-vars
+
+// ─── Redaction helper ─────────────────────────────────────────────────────
+// Replaces the token (and its URL-encoded form) anywhere it appears in a
+// string. Called on every string that is logged or thrown as an error so
+// the token can never surface in stdout, stderr, or CI logs.
+function redact(str) {
+ // Match Bearer prefix too in case the header value is ever echoed back.
+ return String(str)
+ .replace(/Bearer\s+[A-Za-z0-9_\-\.]+/g, 'Bearer [REDACTED]')
+ .replace(/ghp_[A-Za-z0-9]+/g, '[REDACTED]')
+ .replace(/ghs_[A-Za-z0-9]+/g, '[REDACTED]')
+ .replace(/github_pat_[A-Za-z0-9_]+/g, '[REDACTED]');
+}
+
+// ─── Input validation ─────────────────────────────────────────────────────
+// Validate inputs that end up in URLs or file paths before using them.
+function validateRepo(repo) {
+ // Must be «owner/repo» with safe characters only — prevents URL injection.
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) {
+ console.error(`Error: --repo "${repo}" is not a valid owner/repo value.`);
+ process.exit(1);
+ }
+}
+
+function validateBranch(branch) {
+ // Branches can contain letters, numbers, / . - _ but not shell metacharacters.
+ if (!/^[A-Za-z0-9/._\-]+$/.test(branch)) {
+ console.error(`Error: --branch "${branch}" contains invalid characters.`);
+ process.exit(1);
+ }
+}
+
+// ─── Runtime inputs ───────────────────────────────────────────────────────
+const REPO = args['repo'];
+validateRepo(REPO);
+
+const BRANCH = args['branch'] ?? '';
+if (BRANCH) validateBranch(BRANCH);
+
+// Tag-pattern validation — only printable ASCII, no shell metacharacters.
+if (TAG_PATTERN && !/^[A-Za-z0-9._\-/]+$/.test(TAG_PATTERN)) {
+ console.error(`Error: --tag-pattern "${TAG_PATTERN}" contains invalid characters.`);
+ process.exit(1);
+}
+
+const LABEL = args['label'] ?? BRANCH;
+const RELEASE_BRANCH = args['release-branch'] ?? BRANCH;
+const RELEASE_VERSION = args['release-version'] ?? BRANCH;
+const OUTPUT = args['output'];
+const MAX_RUNS = Math.min(parseInt(args['max-runs'], 10), 100);
+const EXISTING_PATH = args['existing'];
+const SKIP_ANNOTATIONS = args['skip-annotations'] ?? false;
+
+// ─── HTTP helper ──────────────────────────────────────────────────────────
+const BASE = 'https://api.github.com';
+
+async function ghFetch(path) {
+ const url = `${BASE}${path}`;
+ let res;
+ try {
+ res = await fetch(url, { headers: _HEADERS });
+ } catch (networkErr) {
+ // Network errors from fetch() never contain token data, but redact anyway.
+ throw new Error(`Network error fetching ${url}: ${redact(networkErr.message)}`);
+ }
+ if (!res.ok) {
+ // API error bodies are redacted before being included in the thrown message
+ // because GitHub sometimes echoes request context in 4xx responses.
+ const body = await res.text().catch(() => '');
+ throw new Error(`GitHub API ${res.status} for ${url}: ${redact(body.slice(0, 200))}`);
+ }
+ return res.json();
+}
+
+// Paginate through all pages of a list endpoint (up to maxItems items).
+async function ghFetchAll(path, arrayKey, maxItems = 500) {
+ const items = [];
+ let page = 1;
+ while (items.length < maxItems) {
+ const perPage = Math.min(100, maxItems - items.length);
+ const data = await ghFetch(`${path}${path.includes('?') ? '&' : '?'}per_page=${perPage}&page=${page}`);
+ const batch = data[arrayKey] ?? [];
+ items.push(...batch);
+ if (batch.length < perPage) break; // last page
+ page++;
+ }
+ return items;
+}
+
+// ─── Tag-based helpers (RC mode) ────────────────────────────────────────────
+
+/**
+ * Fetch all git refs that match a tag prefix, e.g. "v2.0" matches v2.0.0-rc1 etc.
+ * Uses /repos/{owner}/{repo}/git/matching-refs/tags/{pattern}.
+ */
+async function fetchTagRefs(pattern) {
+ return ghFetch(`/repos/${REPO}/git/matching-refs/tags/${encodeURIComponent(pattern)}`);
+}
+
+/**
+ * Fetch all check runs for a specific commit SHA.
+ * Paginates automatically; returns the check_runs array.
+ */
+async function fetchCheckRunsByCommit(sha) {
+ return ghFetchAll(
+ `/repos/${REPO}/commits/${encodeURIComponent(sha)}/check-runs`,
+ 'check_runs',
+ 500,
+ );
+}
+
+/**
+ * Build a dashboard run object from check-runs fetched by commit SHA.
+ * Mirrors the branch-mode job-mapping logic so the output schema is identical.
+ */
+function buildRunObjectFromCheckRuns(checkRuns) {
+ // Status priority for deduplication: lower rank wins.
+ const STATUS_RANK = { passed: 0, failed: 1, skipped: 2 };
+
+ // First pass: map all check-runs to dashboard job shape.
+ const allJobs = checkRuns.map((cr) => {
+ const status = mapStatus(cr.conclusion);
+ const type = classifyJobType(cr.app?.slug ?? '', cr.name);
+
+ let durationSeconds = 0;
+ if (cr.started_at && cr.completed_at) {
+ durationSeconds = Math.round(
+ (new Date(cr.completed_at) - new Date(cr.started_at)) / 1000,
+ );
+ }
+
+ const stats = {
+ total: 1,
+ passed: status === 'passed' ? 1 : 0,
+ failed: status === 'failed' ? 1 : 0,
+ skipped: status === 'skipped' ? 1 : 0,
+ duration_seconds: durationSeconds,
+ pass_rate: status === 'passed' ? 100 : 0,
+ };
+
+ return {
+ job_id: String(cr.id),
+ name: cr.name,
+ type,
+ status,
+ stats,
+ annotations: [],
+ annotation_count: 0,
+ tests: [
+ {
+ test_id: `${cr.id}-test`,
+ name: cr.name,
+ package: REPO,
+ status,
+ stats,
+ cases: [],
+ },
+ ],
+ };
+ });
+
+ // Second pass: deduplicate by name, keeping the highest-priority status.
+ // GitHub returns the same check name from multiple workflows on the same commit.
+ const byName = new Map();
+ for (const job of allJobs) {
+ const existing = byName.get(job.name);
+ if (!existing) {
+ byName.set(job.name, job);
+ } else {
+ const rank = (s) => STATUS_RANK[s] ?? 3;
+ if (rank(job.status) < rank(existing.status)) {
+ byName.set(job.name, job);
+ }
+ }
+ }
+
+ const dashboardJobs = [...byName.values()];
+ if (dashboardJobs.length !== allJobs.length) {
+ console.log(` Deduped ${allJobs.length} check-runs → ${dashboardJobs.length} unique job names`);
+ }
+
+ return dashboardJobs;
+}
+
+// ─── Tag mode — main flow ─────────────────────────────────────────────────
+
+async function runTagMode() {
+ console.log(`[tag mode] Fetching RC tags for ${REPO} pattern="${TAG_PATTERN}"`);
+
+ const allRefs = await fetchTagRefs(TAG_PATTERN);
+
+ // Keep only refs containing "-rc" (case-insensitive), like the Python script.
+ const rcRefs = allRefs.filter((r) => r.ref.toLowerCase().includes('-rc'));
+
+ if (rcRefs.length === 0) {
+ console.error(`No RC tags found matching "${TAG_PATTERN}"`);
+ process.exit(1);
+ }
+
+ console.log(`Found ${rcRefs.length} RC tag(s): ${rcRefs.map((r) => r.ref.replace('refs/tags/', '')).join(', ')}`);
+
+ const runObjects = [];
+ const timestamp = new Date().toISOString();
+
+ for (const ref of [...rcRefs].sort((a, b) => a.ref.localeCompare(b.ref))) {
+ const tagName = ref.ref.replace('refs/tags/', '');
+ const sha = ref.object.sha;
+ console.log(`\nProcessing ${tagName} (${sha.slice(0, 12)})`);
+
+ let checkRuns;
+ try {
+ checkRuns = await fetchCheckRunsByCommit(sha);
+ } catch (err) {
+ console.warn(` Warning: could not fetch check-runs for ${tagName}: ${redact(err.message)}`);
+ continue;
+ }
+ console.log(` ${checkRuns.length} check run(s)`);
+
+ const dashboardJobs = buildRunObjectFromCheckRuns(checkRuns);
+
+ // Enrich failed jobs with annotations (same logic as branch mode).
+ if (!SKIP_ANNOTATIONS) {
+ const failedJobs = dashboardJobs.filter((j) => j.status === 'failed');
+ if (failedJobs.length > 0) {
+ let annotTotal = 0;
+ const ANNOT_BATCH = 5;
+ for (let i = 0; i < failedJobs.length; i += ANNOT_BATCH) {
+ await Promise.all(
+ failedJobs.slice(i, i + ANNOT_BATCH).map(async (dashJob) => {
+ try {
+ const raw = await fetchAnnotations(dashJob.job_id);
+ const failures = raw.filter(
+ (a) => a.annotation_level === 'failure' || a.annotation_level === 'warning',
+ );
+ if (failures.length > 0) {
+ dashJob.annotations = failures.map((ann, idx) => ({
+ id: `ann-${dashJob.job_id}-${idx}`,
+ name: extractAnnotationTestName(ann),
+ path: ann.path ?? null,
+ line: ann.start_line ?? null,
+ message: extractAnnotationDetail(ann),
+ level: ann.annotation_level,
+ }));
+ dashJob.annotation_count = failures.length;
+ annotTotal += failures.length;
+ }
+ } catch (err) {
+ console.warn(` Warning: annotations unavailable for "${dashJob.name}": ${redact(err.message)}`);
+ }
+ }),
+ );
+ }
+ if (annotTotal > 0) {
+ console.log(` ${annotTotal} test failure annotation(s) found`);
+ }
+ }
+ }
+
+ const passed = dashboardJobs.filter((j) => j.status === 'passed').length;
+ const failed = dashboardJobs.filter((j) => j.status === 'failed').length;
+ const skipped = dashboardJobs.filter((j) => j.status === 'skipped').length;
+ const total = dashboardJobs.length;
+ const totalAnnotations = dashboardJobs.reduce((acc, j) => acc + j.annotation_count, 0);
+
+ const summary = {
+ total_jobs: total,
+ total_tests: total,
+ total_cases: 0,
+ total_test_failures: totalAnnotations,
+ annotations_fetched: !SKIP_ANNOTATIONS,
+ passed,
+ failed,
+ skipped,
+ duration_seconds: dashboardJobs.reduce((acc, j) => acc + j.stats.duration_seconds, 0),
+ pass_rate: total > 0 ? parseFloat(((passed / total) * 100).toFixed(1)) : 0,
+ };
+
+ console.log(` ${total} jobs | ${passed} passed | ${failed} failed | ${skipped} skipped | pass rate ${summary.pass_rate}%`);
+
+ runObjects.push({
+ release_branch: TAG_PATTERN,
+ release_version: tagName,
+ repo: REPO,
+ run_id: `Tag-${tagName}`,
+ branch: tagName,
+ commit_sha: sha,
+ timestamp,
+ summary,
+ jobs: dashboardJobs,
+ });
+ }
+
+ if (runObjects.length === 0) {
+ console.error('No run objects produced — aborting.');
+ process.exit(1);
+ }
+
+ // Optionally merge with existing file.
+ let output = runObjects;
+ if (EXISTING_PATH) {
+ try {
+ const resolvedExisting = resolve(EXISTING_PATH);
+ const existing = JSON.parse(readFileSync(resolvedExisting, 'utf8'));
+ const arr = Array.isArray(existing) ? existing : [existing];
+ for (const runObj of runObjects) {
+ const idx = arr.findIndex((r) => r.release_version === runObj.release_version);
+ if (idx >= 0) arr[idx] = runObj; else arr.push(runObj);
+ }
+ output = arr;
+ } catch {
+ output = runObjects;
+ }
+ }
+
+ mkdirSync(dirname(OUTPUT), { recursive: true });
+ writeFileSync(OUTPUT, JSON.stringify(output, null, 2), 'utf8');
+ console.log(`\nWrote ${OUTPUT} (${runObjects.length} RC tag run(s))`);
+}
+
+// ─── Check-run annotation helpers ────────────────────────────────────────────
+
+/** Extract the numeric check-run ID from a check_run_url field on a job. */
+function extractCheckRunId(checkRunUrl) {
+ if (!checkRunUrl || typeof checkRunUrl !== 'string') return null;
+ const m = checkRunUrl.match(/\/check-runs\/(\d+)(?:$|\?)/);
+ return m ? m[1] : null;
+}
+
+/**
+ * Fetch all annotations for a check run.
+ * The endpoint returns a JSON array directly (not wrapped in an object key)
+ * so we cannot reuse ghFetchAll — we paginate manually.
+ */
+async function fetchAnnotations(checkRunId) {
+ const items = [];
+ let page = 1;
+ while (true) {
+ const url = `${BASE}/repos/${REPO}/check-runs/${checkRunId}/annotations?per_page=100&page=${page}`;
+ let res;
+ try {
+ res = await fetch(url, { headers: _HEADERS });
+ } catch (networkErr) {
+ throw new Error(`Network error fetching annotations: ${redact(networkErr.message)}`);
+ }
+ if (!res.ok) {
+ const body = await res.text().catch(() => '');
+ throw new Error(`GitHub API ${res.status} for annotations: ${redact(body.slice(0, 200))}`);
+ }
+ const batch = await res.json();
+ if (!Array.isArray(batch) || batch.length === 0) break;
+ items.push(...batch);
+ if (batch.length < 100) break;
+ page++;
+ }
+ return items;
+}
+
+/** Extract a clean test name from a GitHub check-run annotation. */
+function extractAnnotationTestName(ann) {
+ // gotestsum --format=github-actions puts the test name in the title field.
+ const title = (ann.title ?? '').trim();
+ if (/^Test[A-Z_]/.test(title)) return title;
+
+ // Also try the first line of message (some tools use that).
+ const firstLine = (ann.message ?? '').split('\n')[0].trim();
+ if (/^Test[A-Z_]/.test(firstLine)) return firstLine;
+
+ // Fall back: look for "--- FAIL: TestXxx" pattern in the message body.
+ const failMatch = (ann.message ?? '').match(/---\s*(?:FAIL|ERROR):\s+(Test\S+)/);
+ if (failMatch) return failMatch[1];
+
+ // Last resort: use title or first message line verbatim.
+ return title || firstLine || 'Unknown test';
+}
+
+/** Extract failure detail lines from an annotation message (strips test-name header). */
+function extractAnnotationDetail(ann) {
+ return (ann.message ?? '')
+ .split('\n')
+ // Drop lines that are just the test name or a PASS/FAIL marker.
+ .filter((l) => l.trim() && !/^---\s*(FAIL|PASS):/.test(l.trim()))
+ .join('\n')
+ .trim();
+}
+
+// ─── Type classification ───────────────────────────────────────────────────
+// Classifies a job into one of the four dashboard types based on the GitHub
+// workflow file name and job name. Adjust the keywords to match your
+// organisation's naming conventions.
+function classifyJobType(workflowName = '', jobName = '') {
+ const combined = `${workflowName} ${jobName}`.toLowerCase();
+
+ if (/\blint\b/.test(combined)) return 'Lint';
+ if (/\bui\b|\bfrontend\b|\bember\b|\bplaywright\b/.test(combined)) return 'UI';
+ if (/integrat|envoy|nomad|vault|consul-container|deployer/.test(combined)) return 'Integration';
+ return 'Other';
+}
+
+// ─── Status mapping ────────────────────────────────────────────────────────
+// Maps GitHub job/run conclusion strings to the dashboard status values.
+function mapStatus(conclusion) {
+ switch (conclusion) {
+ case 'success': return 'passed';
+ case 'failure': return 'failed';
+ case 'cancelled':
+ case 'skipped':
+ case 'neutral': return 'skipped';
+ case 'timed_out': return 'failed';
+ default: return conclusion ?? 'skipped';
+ }
+}
+
+// ─── Main ──────────────────────────────────────────────────────────────────
+async function main() {
+ console.log(`Fetching workflow runs for ${REPO} branch=${BRANCH} (max ${MAX_RUNS})`);
+
+ // 1. Get the most recent completed workflow runs for this branch.
+ const runs = await ghFetchAll(
+ `/repos/${REPO}/actions/runs?branch=${encodeURIComponent(BRANCH)}&status=completed`,
+ 'workflow_runs',
+ MAX_RUNS,
+ );
+
+ if (runs.length === 0) {
+ console.error(`No completed workflow runs found for branch "${BRANCH}".`);
+ process.exit(1);
+ }
+
+ // Use the most recent run's commit SHA and timestamp as the "snapshot" metadata.
+ const latestRun = runs[0];
+ const commitSha = latestRun.head_sha;
+ const timestamp = new Date().toISOString();
+
+ console.log(`Found ${runs.length} workflow runs. Latest commit: ${commitSha.slice(0, 12)}`);
+
+ // 2. For each workflow run, fetch its jobs.
+ // We do this concurrently in batches of 8 to be polite to the API.
+ const BATCH = 8;
+ const allJobs = [];
+
+ for (let i = 0; i < runs.length; i += BATCH) {
+ const batch = runs.slice(i, i + BATCH);
+ const results = await Promise.all(
+ batch.map(async (run) => {
+ try {
+ const jobs = await ghFetchAll(
+ `/repos/${REPO}/actions/runs/${run.id}/jobs`,
+ 'jobs',
+ 200,
+ );
+ return jobs.map((job) => ({ job, workflowName: run.name }));
+ } catch (err) {
+ // Redact before logging — API error messages may echo request context.
+ console.warn(` Warning: could not fetch jobs for run ${run.id}: ${redact(err.message)}`);
+ return [];
+ }
+ }),
+ );
+ allJobs.push(...results.flat());
+ process.stdout.write(` Fetched jobs for ${Math.min(i + BATCH, runs.length)}/${runs.length} runs\r`);
+ }
+ console.log(`\n Total jobs collected: ${allJobs.length}`);
+
+ // 3. Deduplicate by job name (keep most recent occurrence — runs are newest-first).
+ // This ensures each logical job appears once in the summary.
+ const seen = new Set();
+ const dedupedJobs = [];
+ for (const { job, workflowName } of allJobs) {
+ if (!seen.has(job.name)) {
+ seen.add(job.name);
+ dedupedJobs.push({ job, workflowName });
+ }
+ }
+ console.log(` After deduplication: ${dedupedJobs.length} unique jobs`);
+
+ // 4. Map each job to the dashboard schema.
+ const dashboardJobs = dedupedJobs.map(({ job, workflowName }) => {
+ const status = mapStatus(job.conclusion);
+ const type = classifyJobType(workflowName, job.name);
+
+ // Duration — GitHub provides started_at / completed_at ISO strings
+ let durationSeconds = 0;
+ if (job.started_at && job.completed_at) {
+ durationSeconds = Math.round(
+ (new Date(job.completed_at) - new Date(job.started_at)) / 1000,
+ );
+ }
+
+ const stats = {
+ total: 1,
+ passed: status === 'passed' ? 1 : 0,
+ failed: status === 'failed' ? 1 : 0,
+ skipped: status === 'skipped' ? 1 : 0,
+ duration_seconds: durationSeconds,
+ pass_rate: status === 'passed' ? 100 : 0,
+ };
+
+ // Map individual steps as "cases" if there are any non-trivial steps.
+ const cases = (job.steps ?? [])
+ .filter((s) => s.name !== 'Set up job' && s.name !== 'Complete job')
+ .map((step) => ({
+ case_id: `${job.id}-${step.number}`,
+ name: step.name,
+ status: mapStatus(step.conclusion),
+ duration_seconds: (() => {
+ if (step.started_at && step.completed_at) {
+ return Math.round((new Date(step.completed_at) - new Date(step.started_at)) / 1000);
+ }
+ return 0;
+ })(),
+ }));
+
+ return {
+ job_id: String(job.id),
+ name: job.name,
+ type,
+ status,
+ stats,
+ // annotations: populated below for failed jobs once check-run data is fetched.
+ annotations: [],
+ annotation_count: 0,
+ tests: [
+ {
+ test_id: `${job.id}-test`,
+ name: job.name,
+ package: REPO,
+ status,
+ stats,
+ cases,
+ },
+ ],
+ };
+ });
+
+ // 4b. Enrich failed jobs with check-run annotations (individual test failures).
+ // Each annotation = one failed test case; message contains the full failure output.
+ // This uses GitHub's annotation API which is populated automatically when
+ // gotestsum is invoked with --format=github-actions.
+ if (!SKIP_ANNOTATIONS) {
+ const failedDashJobs = dashboardJobs.filter((j) => j.status === 'failed');
+ if (failedDashJobs.length > 0) {
+ console.log(`\nFetching check-run annotations for ${failedDashJobs.length} failed job(s)...`);
+
+ // Build a lookup: "job_id" → original GitHub job object (for check_run_url).
+ const jobById = new Map(dedupedJobs.map(({ job }) => [String(job.id), job]));
+
+ let annotJobsFetched = 0;
+ let annotTotal = 0;
+ const ANNOT_BATCH = 5; // conservative batch size
+
+ for (let i = 0; i < failedDashJobs.length; i += ANNOT_BATCH) {
+ const batch = failedDashJobs.slice(i, i + ANNOT_BATCH);
+ await Promise.all(
+ batch.map(async (dashJob) => {
+ const origJob = jobById.get(dashJob.job_id);
+ if (!origJob) return;
+ const checkRunId = extractCheckRunId(origJob.check_run_url);
+ if (!checkRunId) return;
+
+ try {
+ const raw = await fetchAnnotations(checkRunId);
+ const failures = raw.filter((a) => a.annotation_level === 'failure' || a.annotation_level === 'warning');
+ if (failures.length > 0) {
+ dashJob.annotations = failures.map((ann, idx) => ({
+ id: `ann-${checkRunId}-${idx}`,
+ name: extractAnnotationTestName(ann),
+ path: ann.path ?? null,
+ line: ann.start_line ?? null,
+ message: extractAnnotationDetail(ann),
+ level: ann.annotation_level,
+ }));
+ dashJob.annotation_count = failures.length;
+ annotTotal += failures.length;
+ }
+ annotJobsFetched++;
+ } catch (err) {
+ console.warn(` Warning: annotations unavailable for "${dashJob.name}": ${redact(err.message)}`);
+ }
+ }),
+ );
+ process.stdout.write(
+ ` Annotations: ${Math.min(i + ANNOT_BATCH, failedDashJobs.length)}/${failedDashJobs.length} jobs processed\r`,
+ );
+ }
+
+ if (annotJobsFetched > 0) {
+ console.log(`\n ${annotTotal} test failure annotation(s) across ${annotJobsFetched} job(s)`);
+ } else {
+ console.log('\n No annotations found (check-runs may not emit annotations for this workflow)');
+ }
+ }
+ } else {
+ console.log(' Skipping annotation fetch (--skip-annotations)');
+ }
+
+ // 5. Build the summary.
+ const passed = dashboardJobs.filter((j) => j.status === 'passed').length;
+ const failed = dashboardJobs.filter((j) => j.status === 'failed').length;
+ const skipped = dashboardJobs.filter((j) => j.status === 'skipped').length;
+ const total = dashboardJobs.length;
+ const totalCases = dashboardJobs.reduce((acc, j) => acc + j.tests[0].cases.length, 0);
+ const totalAnnotations = dashboardJobs.reduce((acc, j) => acc + j.annotation_count, 0);
+
+ const summary = {
+ total_jobs: total,
+ total_tests: total,
+ total_cases: totalCases,
+ total_test_failures: totalAnnotations,
+ annotations_fetched: !SKIP_ANNOTATIONS,
+ passed,
+ failed,
+ skipped,
+ duration_seconds: dashboardJobs.reduce((acc, j) => acc + j.stats.duration_seconds, 0),
+ pass_rate: total > 0 ? parseFloat(((passed / total) * 100).toFixed(1)) : 0,
+ };
+
+ // 6. Build the final run object.
+ const runObject = {
+ release_branch: RELEASE_BRANCH,
+ release_version: RELEASE_VERSION,
+ repo: REPO,
+ run_id: LABEL,
+ branch: BRANCH,
+ commit_sha: commitSha,
+ timestamp,
+ summary,
+ jobs: dashboardJobs,
+ };
+
+ // 7. Optionally merge with an existing results file (multi-branch / multi-run array).
+ let output;
+ if (EXISTING_PATH) {
+ try {
+ // resolve() normalises the path so relative traversal (../../etc) is
+ // visible in logs and doesn't silently escape the working directory.
+ const resolvedExisting = resolve(EXISTING_PATH);
+ const existing = JSON.parse(readFileSync(resolvedExisting, 'utf8'));
+ const arr = Array.isArray(existing) ? existing : [existing];
+ // Replace the entry with the same release_version if it already exists.
+ const idx = arr.findIndex((r) => r.release_version === RELEASE_VERSION);
+ if (idx >= 0) {
+ arr[idx] = runObject;
+ } else {
+ arr.push(runObject);
+ }
+ output = arr;
+ } catch {
+ output = [runObject];
+ }
+ } else {
+ output = [runObject];
+ }
+
+ // 8. Write output.
+ mkdirSync(dirname(OUTPUT), { recursive: true });
+ writeFileSync(OUTPUT, JSON.stringify(output, null, 2), 'utf8');
+
+ console.log(`\nWrote ${OUTPUT}`);
+ console.log(` ${total} jobs | ${passed} passed | ${failed} failed | ${skipped} skipped | pass rate ${summary.pass_rate}%`);
+ if (totalAnnotations > 0) {
+ console.log(` ${totalAnnotations} individual test failure(s) captured via check-run annotations`);
+ } else if (totalCases > 0) {
+ console.log(` ${totalCases} step-level cases extracted`);
+ }
+}
+
+// ─── Process-level safety net ────────────────────────────────────────────
+// Catches anything that escapes main().catch() (e.g. async microtask throws)
+// and ensures the token is never printed via an uncaught rejection dump.
+process.on('unhandledRejection', (reason) => {
+ const msg = reason instanceof Error ? reason.message : String(reason);
+ console.error('\nUnhandled rejection:', redact(msg));
+ process.exit(1);
+});
+
+process.on('uncaughtException', (err) => {
+ console.error('\nUncaught exception:', redact(err.message));
+ process.exit(1);
+});
+
+// Dispatch to the appropriate mode.
+const _entryFn = TAG_PATTERN ? runTagMode : main;
+_entryFn().catch((err) => {
+ console.error('\nFatal:', redact(err.message));
+ process.exit(1);
+});
diff --git a/ui/packages/ci-dashboard/src/app.css b/ui/packages/ci-dashboard/src/app.css
new file mode 100644
index 00000000000..00e0fb559a5
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/app.css
@@ -0,0 +1,845 @@
+/* Copyright IBM Corp. 2024, 2026 */
+/* SPDX-License-Identifier: BUSL-1.1 */
+
+/* ─── Design tokens ─────────────────────────────────────────────────────── */
+:root {
+ --bg: #f0f2f5;
+ --surface: #ffffff;
+ --surface-raised: #ffffff;
+ --surface-subtle: #f8f9fb;
+ --border: #e2e5ea;
+ --border-strong: #c9cdd5;
+ --text: #111827;
+ --text-secondary: #4b5563;
+ --text-muted: #9ca3af;
+ --accent: #2563eb;
+ --accent-hover: #1d4ed8;
+ --accent-subtle: #eff6ff;
+
+ --color-passed: #16a34a;
+ --color-passed-bg: #f0fdf4;
+ --color-passed-border: #bbf7d0;
+ --color-failed: #dc2626;
+ --color-failed-bg: #fef2f2;
+ --color-failed-border: #fecaca;
+ --color-skipped: #6b7280;
+ --color-skipped-bg: #f9fafb;
+ --color-skipped-border:#e5e7eb;
+ --color-warn: #d97706;
+ --color-warn-bg: #fffbeb;
+
+ --type-integration-bg: #f5f3ff;
+ --type-integration-fg: #6d28d9;
+ --type-integration-border: #ddd6fe;
+ --type-lint-bg: #e0f2fe;
+ --type-lint-fg: #0369a1;
+ --type-lint-border: #bae6fd;
+ --type-ui-bg: #fef3c7;
+ --type-ui-fg: #92400e;
+ --type-ui-border: #fde68a;
+ --type-other-bg: #f3f4f6;
+ --type-other-fg: #374151;
+ --type-other-border:#e5e7eb;
+
+ --header-bg: #0f1729;
+ --header-border: #1e2d4a;
+ --header-fg: #e2e8f0;
+ --header-muted: rgba(226,232,240,.45);
+
+ --r-xs: 3px;
+ --r-sm: 6px;
+ --r-md: 10px;
+ --r-lg: 14px;
+ --r-xl: 20px;
+
+ --shadow-xs: 0 1px 2px rgba(0,0,0,.05);
+ --shadow-sm: 0 1px 4px rgba(0,0,0,.07), 0 1px 2px rgba(0,0,0,.04);
+ --shadow-md: 0 4px 16px rgba(0,0,0,.08), 0 2px 6px rgba(0,0,0,.05);
+ --shadow-ring: 0 0 0 3px rgba(37,99,235,.18);
+
+ --font-mono: 'SFMono-Regular', 'Cascadia Code', Consolas, 'Liberation Mono', monospace;
+
+ --transition-fast: 120ms cubic-bezier(.4,0,.2,1);
+ --transition-base: 200ms cubic-bezier(.4,0,.2,1);
+}
+
+/* ─── Reset ─────────────────────────────────────────────────────────────── */
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+html { scroll-behavior: smooth; }
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ min-height: 100vh;
+ line-height: 1.6;
+ font-size: 14px;
+ -webkit-font-smoothing: antialiased;
+}
+
+/* ─── Loading / error ──────────────────────────────────────────────────── */
+.loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ min-height: 100vh;
+ color: var(--text-muted);
+ font-size: 15px;
+}
+.loading::before {
+ content: '';
+ width: 18px;
+ height: 18px;
+ border: 2px solid var(--border);
+ border-top-color: var(--accent);
+ border-radius: 50%;
+ animation: spin .7s linear infinite;
+}
+@keyframes spin { to { transform: rotate(360deg); } }
+
+.error-state {
+ max-width: 460px;
+ margin: 80px auto;
+ padding: 36px 32px;
+ background: var(--surface);
+ border: 1px solid var(--color-failed-border);
+ border-radius: var(--r-lg);
+ box-shadow: var(--shadow-md);
+ text-align: center;
+}
+.error-icon { font-size: 36px; margin-bottom: 14px; }
+.error-state h2 { font-size: 18px; font-weight: 600; margin-bottom: 10px; }
+.error-message { color: var(--color-failed); font-size: 13px; margin-bottom: 16px; font-family: var(--font-mono); background: var(--color-failed-bg); padding: 10px 14px; border-radius: var(--r-sm); }
+.error-hint { font-size: 13px; color: var(--text-secondary); }
+.error-hint code { background: #f3f4f6; padding: 1px 5px; border-radius: var(--r-xs); font-family: var(--font-mono); font-size: 12px; }
+
+/* ─── App-level wrapper ─────────────────────────────────────────────────── */
+#app { min-height: 100vh; display: flex; flex-direction: column; }
+
+/* ─── Header ────────────────────────────────────────────────────────────── */
+.app-header {
+ background: var(--header-bg);
+ border-bottom: 1px solid var(--header-border);
+ padding: 0 28px;
+ display: flex;
+ align-items: center;
+ gap: 0;
+ min-height: 60px;
+ position: sticky;
+ top: 0;
+ z-index: 100;
+}
+
+.header-brand-block {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding-right: 24px;
+ border-right: 1px solid var(--header-border);
+ min-height: 60px;
+ flex-shrink: 0;
+}
+.brand-icon {
+ width: 28px;
+ height: 28px;
+ background: var(--accent);
+ border-radius: 7px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ font-weight: 800;
+ color: #fff;
+ letter-spacing: -.5px;
+ flex-shrink: 0;
+}
+.brand-name { font-size: 15px; font-weight: 700; color: #fff; }
+.brand-slash { color: var(--header-muted); font-size: 18px; margin: 0 2px; }
+.brand-sub { font-size: 13px; color: var(--header-muted); font-weight: 400; }
+
+.header-meta-block {
+ display: flex;
+ gap: 2px;
+ align-items: center;
+ flex: 1;
+ overflow: hidden;
+ min-height: 60px;
+ padding: 0 20px;
+}
+.meta-chip {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 12px;
+ background: rgba(255,255,255,.06);
+ border: 1px solid rgba(255,255,255,.08);
+ border-radius: 100px;
+ flex-shrink: 0;
+ margin-right: 6px;
+}
+.meta-chip-label {
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .08em;
+ color: var(--header-muted);
+ white-space: nowrap;
+}
+.meta-chip-value {
+ font-size: 12px;
+ color: var(--header-fg);
+ white-space: nowrap;
+}
+.meta-chip-value.mono {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ background: rgba(255,255,255,.08);
+ padding: 1px 6px;
+ border-radius: var(--r-xs);
+}
+
+.header-controls-block {
+ padding-left: 20px;
+ border-left: 1px solid var(--header-border);
+ min-height: 60px;
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+}
+.run-selector-label {
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .08em;
+ color: var(--header-muted);
+ margin-right: 8px;
+}
+.run-select {
+ appearance: none;
+ background: rgba(255,255,255,.08) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23aab' d='M2 4l4 4 4-4z'/%3E%3C/svg%3E") no-repeat right 10px center;
+ border: 1px solid rgba(255,255,255,.15);
+ color: var(--header-fg);
+ padding: 6px 30px 6px 12px;
+ border-radius: var(--r-sm);
+ font-size: 13px;
+ cursor: pointer;
+ min-width: 220px;
+ transition: border-color var(--transition-fast), background var(--transition-fast);
+}
+.run-select:hover { background-color: rgba(255,255,255,.12); border-color: rgba(255,255,255,.25); }
+.run-select:focus { outline: none; box-shadow: var(--shadow-ring); }
+.run-select option { background: #1e293b; color: #fff; }
+
+/* ─── Main layout ───────────────────────────────────────────────────────── */
+.main-content {
+ max-width: 1440px;
+ width: 100%;
+ margin: 0 auto;
+ padding: 28px 28px 48px;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ flex: 1;
+}
+
+/* ─── Summary bar ───────────────────────────────────────────────────────── */
+.summary-bar {
+ display: grid;
+ grid-template-columns: auto 1px 1fr;
+ gap: 0;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+ box-shadow: var(--shadow-sm);
+ overflow: hidden;
+}
+
+.summary-donut-section {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ padding: 24px 32px;
+}
+.summary-divider { background: var(--border); }
+
+.summary-stats-section {
+ display: flex;
+ align-items: stretch;
+ padding: 0;
+}
+
+.stat-card {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 20px 16px;
+ border-right: 1px solid var(--border);
+ gap: 4px;
+ transition: background var(--transition-fast);
+ cursor: default;
+}
+.stat-card:last-child { border-right: none; }
+.stat-card:hover { background: var(--surface-subtle); }
+
+.stat-num {
+ font-size: 32px;
+ font-weight: 700;
+ line-height: 1;
+ letter-spacing: -.03em;
+ font-variant-numeric: tabular-nums;
+}
+.stat-label {
+ font-size: 11px;
+ font-weight: 500;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ white-space: nowrap;
+}
+.stat-sub {
+ font-size: 11px;
+ color: var(--text-muted);
+ margin-top: 1px;
+}
+
+.stat-passed .stat-num { color: var(--color-passed); }
+.stat-failed .stat-num { color: var(--color-failed); }
+.stat-skipped .stat-num { color: var(--color-skipped); }
+.stat-total .stat-num { color: var(--accent); }
+.stat-cases .stat-num { color: var(--text-secondary); }
+
+/* Donut */
+.donut-wrap {
+ position: relative;
+ flex-shrink: 0;
+}
+.donut { display: block; transform: rotate(-90deg); }
+.donut-track { fill: none; stroke: #f0f0f0; stroke-width: 9; }
+.donut-bg { fill: none; stroke: #e5e7eb; stroke-width: 9; }
+.donut-fill {
+ fill: none;
+ stroke-width: 9;
+ stroke-linecap: round;
+ transition: stroke-dasharray var(--transition-base);
+}
+.rate-great .donut-fill { stroke: var(--color-passed); }
+.rate-good .donut-fill { stroke: #65a30d; }
+.rate-warn .donut-fill { stroke: var(--color-warn); }
+.rate-bad .donut-fill { stroke: var(--color-failed); }
+
+.donut-center-text {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ pointer-events: none;
+}
+.donut-pct { font-size: 20px; font-weight: 700; color: var(--text); line-height: 1; }
+.donut-label { font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted); margin-top: 2px; }
+
+.donut-meta { display: flex; flex-direction: column; gap: 6px; }
+.donut-meta-item {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ font-size: 13px;
+ color: var(--text-secondary);
+}
+.donut-meta-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+.dot-passed { background: var(--color-passed); }
+.dot-failed { background: var(--color-failed); }
+.dot-skipped { background: #d1d5db; }
+.donut-meta-val { font-weight: 600; color: var(--text); min-width: 24px; }
+
+/* ─── Filters ───────────────────────────────────────────────────────────── */
+.filters {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ flex-wrap: wrap;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+ padding: 14px 20px;
+ box-shadow: var(--shadow-xs);
+}
+
+.filter-group { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
+.filter-label {
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: var(--text-muted);
+ white-space: nowrap;
+ min-width: 42px;
+}
+.filter-divider { width: 1px; height: 24px; background: var(--border); flex-shrink: 0; }
+.filter-buttons { display: flex; gap: 4px; flex-wrap: wrap; }
+
+.filter-btn {
+ padding: 5px 13px;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ border-radius: 100px;
+ font-size: 12px;
+ font-weight: 500;
+ cursor: pointer;
+ color: var(--text-secondary);
+ transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
+ white-space: nowrap;
+ line-height: 1.4;
+}
+.filter-btn:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+ background: var(--accent-subtle);
+}
+.filter-btn:focus-visible { outline: none; box-shadow: var(--shadow-ring); }
+.filter-btn.active {
+ background: var(--accent);
+ border-color: var(--accent);
+ color: #fff;
+ font-weight: 600;
+ box-shadow: 0 1px 4px rgba(37,99,235,.35);
+}
+
+.filter-btn.status-passed.active { background: var(--color-passed); border-color: var(--color-passed); box-shadow: 0 1px 4px rgba(22,163,74,.35); }
+.filter-btn.status-failed.active { background: var(--color-failed); border-color: var(--color-failed); box-shadow: 0 1px 4px rgba(220,38,38,.35); }
+.filter-btn.status-skipped.active { background: var(--color-skipped); border-color: var(--color-skipped); box-shadow: none; }
+
+/* ─── Table section ─────────────────────────────────────────────────────── */
+.table-section {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+ overflow: hidden;
+ box-shadow: var(--shadow-sm);
+}
+
+.table-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 14px 20px 12px;
+ border-bottom: 1px solid var(--border);
+ background: var(--surface-subtle);
+ gap: 12px;
+ flex-wrap: wrap;
+}
+.table-title {
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--text);
+}
+.table-count {
+ font-size: 12px;
+ color: var(--text-muted);
+ background: var(--bg);
+ border: 1px solid var(--border);
+ padding: 2px 10px;
+ border-radius: 100px;
+}
+
+.job-table {
+ width: 100%;
+ border-collapse: collapse;
+}
+.job-table thead th {
+ padding: 10px 16px;
+ text-align: left;
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: var(--text-muted);
+ border-bottom: 1px solid var(--border);
+ white-space: nowrap;
+ background: var(--surface-subtle);
+ user-select: none;
+}
+.job-table thead th.th-right { text-align: right; }
+.job-table thead th.th-center { text-align: center; }
+
+/* Job rows */
+.job-row {
+ border-bottom: 1px solid var(--border);
+ cursor: pointer;
+ transition: background var(--transition-fast);
+}
+.job-row:hover { background: #fafbfc; }
+.job-row.expanded { background: var(--accent-subtle); }
+.job-row.expanded:hover { background: #e8f0fe; }
+
+.job-row.row-failed {
+ border-left: 3px solid var(--color-failed);
+ background: var(--color-failed-bg);
+}
+.job-row.row-failed:hover { background: #fde8e8; }
+.job-row.row-skipped { opacity: .65; }
+.job-row.row-skipped:hover { opacity: .85; }
+
+.job-row td { padding: 11px 16px; vertical-align: middle; }
+
+.td-name { max-width: 340px; }
+.job-name-inner {
+ display: flex;
+ align-items: center;
+ gap: 9px;
+}
+.chevron {
+ color: var(--text-muted);
+ font-size: 10px;
+ flex-shrink: 0;
+ user-select: none;
+ width: 14px;
+ transition: transform var(--transition-fast);
+}
+.job-row.expanded .chevron { color: var(--accent); }
+.job-name-text {
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--text);
+ word-break: break-word;
+ line-height: 1.4;
+}
+
+.td-num { text-align: right; font-variant-numeric: tabular-nums; font-size: 13px; }
+.td-center { text-align: center; }
+
+/* Pass-rate cell */
+.td-rate { min-width: 160px; }
+.rate-cell { display: flex; align-items: center; gap: 10px; }
+.rate-bar {
+ flex: 1;
+ height: 5px;
+ background: #eaecef;
+ border-radius: 10px;
+ overflow: hidden;
+}
+.rate-fill { height: 100%; border-radius: 10px; transition: width var(--transition-base); }
+.rate-fill-great { background: var(--color-passed); }
+.rate-fill-good { background: #65a30d; }
+.rate-fill-warn { background: var(--color-warn); }
+.rate-fill-bad { background: var(--color-failed); }
+.rate-pct {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--text-secondary);
+ min-width: 36px;
+ text-align: right;
+ font-variant-numeric: tabular-nums;
+}
+
+/* ─── Badges ────────────────────────────────────────────────────────────── */
+.type-badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 2px 9px;
+ border-radius: var(--r-xs);
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: .02em;
+ white-space: nowrap;
+ border: 1px solid transparent;
+}
+.type-integration { background: var(--type-integration-bg); color: var(--type-integration-fg); border-color: var(--type-integration-border); }
+.type-lint { background: var(--type-lint-bg); color: var(--type-lint-fg); border-color: var(--type-lint-border); }
+.type-ui { background: var(--type-ui-bg); color: var(--type-ui-fg); border-color: var(--type-ui-border); }
+.type-other { background: var(--type-other-bg); color: var(--type-other-fg); border-color: var(--type-other-border); }
+
+.status-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ padding: 3px 9px;
+ border-radius: var(--r-xs);
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: capitalize;
+ white-space: nowrap;
+ border: 1px solid transparent;
+}
+.status-badge::before {
+ content: '';
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+.badge-passed { background: var(--color-passed-bg); color: var(--color-passed); border-color: var(--color-passed-border); }
+.badge-passed::before { background: var(--color-passed); }
+.badge-failed { background: var(--color-failed-bg); color: var(--color-failed); border-color: var(--color-failed-border); }
+.badge-failed::before { background: var(--color-failed); }
+.badge-skipped { background: var(--color-skipped-bg); color: var(--color-skipped); border-color: var(--color-skipped-border); }
+.badge-skipped::before { background: var(--color-skipped); }
+.badge-unknown { background: #f3f4f6; color: #6b7280; border-color: #e5e7eb; }
+.badge-unknown::before { background: #9ca3af; }
+
+/* ─── Expanded tests sub-table ──────────────────────────────────────────── */
+.tests-row { border-bottom: 1px solid var(--border); }
+.tests-row > td {
+ padding: 0;
+ background: #fbfcfe;
+}
+.tests-inner {
+ border-top: 1px solid #dce6f9;
+ margin-left: 39px;
+}
+.tests-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 13px;
+}
+.tests-table thead th {
+ padding: 8px 14px;
+ text-align: left;
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: var(--text-muted);
+ background: #f1f5fd;
+ border-bottom: 1px solid #dce6f9;
+}
+.tests-table thead th.th-right { text-align: right; }
+.test-row td {
+ padding: 9px 14px;
+ border-bottom: 1px solid #e8edf7;
+ vertical-align: middle;
+}
+.test-row:last-child td { border-bottom: none; }
+.test-row.status-failed { background: #fff5f5; }
+.test-row.status-skipped { opacity: .7; }
+
+.test-name-block { display: flex; flex-direction: column; gap: 2px; }
+.test-name {
+ font-family: var(--font-mono);
+ font-size: 12px;
+ color: var(--text-secondary);
+ word-break: break-all;
+}
+.test-package {
+ font-size: 11px;
+ color: var(--text-muted);
+ font-family: var(--font-mono);
+}
+
+.cell-failed { color: var(--color-failed); font-weight: 600; }
+.cell-passed { color: var(--color-passed); font-weight: 600; }
+.cell-right { text-align: right; font-variant-numeric: tabular-nums; }
+
+.no-tests {
+ padding: 16px 20px;
+ font-size: 13px;
+ color: var(--text-muted);
+ font-style: italic;
+}
+.no-tests .hint { font-style: normal; color: var(--text-secondary); }
+.no-tests code { font-family: var(--font-mono); font-size: 11px; background: #eeeef3; padding: 1px 4px; border-radius: 3px; }
+
+/* ─── Annotation count badge (job name area) ───────────────────────────── */
+.annot-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ margin-left: 8px;
+ padding: 2px 8px;
+ background: #fff0f0;
+ color: var(--color-failed);
+ border: 1px solid #fecaca;
+ border-radius: 100px;
+ font-size: 11px;
+ font-weight: 600;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+/* ─── Annotations panel (expanded row — test-level failure data) ────────── */
+.annotations-inner {
+ border-top: 2px solid #fca5a5;
+ margin-left: 39px;
+ background: #fffafa;
+}
+.ann-header {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 14px 7px;
+ border-bottom: 1px solid #fde8e8;
+ background: #fff5f5;
+}
+.ann-title {
+ font-size: 11px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: #c0392b;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+.ann-count {
+ background: var(--color-failed);
+ color: #fff;
+ border-radius: 100px;
+ padding: 1px 7px;
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: .02em;
+}
+.ann-source {
+ font-size: 11px;
+ color: var(--text-muted);
+ font-style: italic;
+ margin-left: auto;
+}
+
+.ann-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 13px;
+}
+.ann-th {
+ padding: 7px 14px;
+ text-align: left;
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: var(--text-muted);
+ background: #fff8f8;
+ border-bottom: 1px solid #fde8e8;
+}
+.ann-row td {
+ padding: 9px 14px;
+ border-bottom: 1px solid #fde8e8;
+ vertical-align: top;
+}
+.ann-row:last-child td { border-bottom: none; }
+.ann-row.ann-level-warning td { background: #fffbeb; }
+
+.ann-name-cell {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ min-width: 200px;
+ max-width: 340px;
+}
+.ann-dot {
+ flex-shrink: 0;
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--color-failed);
+ margin-top: 4px;
+}
+.ann-level-warning .ann-dot { background: var(--color-skipped); }
+.ann-name {
+ font-family: var(--font-mono);
+ font-size: 12px;
+ color: var(--text);
+ word-break: break-all;
+ font-weight: 600;
+}
+
+.ann-file-cell { max-width: 220px; vertical-align: top; }
+.ann-file-link {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: #2563eb;
+ text-decoration: none;
+ word-break: break-all;
+}
+.ann-file-link:hover { text-decoration: underline; }
+.ann-file {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: var(--text-secondary);
+ word-break: break-all;
+}
+.ann-line-num {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: var(--text-muted);
+}
+
+.ann-message-cell { width: 100%; }
+.ann-detail {
+ cursor: pointer;
+}
+.ann-summary {
+ font-size: 11px;
+ color: #2563eb;
+ cursor: pointer;
+ user-select: none;
+ list-style: none;
+}
+.ann-summary::-webkit-details-marker { display: none; }
+.ann-summary::before {
+ content: '▸ ';
+ font-size: 9px;
+}
+details[open] .ann-summary::before { content: '▾ '; }
+.ann-pre {
+ margin: 6px 0 0;
+ padding: 8px 10px;
+ background: #1e1e2e;
+ color: #cdd6f4;
+ border-radius: 6px;
+ font-family: var(--font-mono);
+ font-size: 11px;
+ line-height: 1.6;
+ white-space: pre-wrap;
+ word-break: break-word;
+ max-height: 300px;
+ overflow-y: auto;
+}
+.ann-no-detail { font-size: 12px; color: var(--text-muted); }
+
+/* ─── Table footer / empty ──────────────────────────────────────────────── */
+.table-footer {
+ padding: 10px 20px;
+ font-size: 12px;
+ color: var(--text-muted);
+ border-top: 1px solid var(--border);
+ background: var(--surface-subtle);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.empty-state {
+ padding: 60px 24px;
+ text-align: center;
+}
+.empty-state-icon { font-size: 32px; margin-bottom: 12px; }
+.empty-state-title { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
+.empty-state-sub { font-size: 13px; color: var(--text-muted); }
+
+/* ─── Responsive ────────────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .app-header { flex-wrap: wrap; padding: 12px 16px; min-height: auto; gap: 10px; }
+ .header-meta-block { display: none; }
+ .header-controls-block { border-left: none; padding-left: 0; }
+ .main-content { padding: 16px; }
+ .summary-bar { grid-template-columns: 1fr; }
+ .summary-divider { display: none; }
+ .summary-stats-section { flex-wrap: wrap; }
+ .run-select { min-width: 160px; }
+}
+
+@media (max-width: 600px) {
+ .td-rate, .tests-table .th-right, .tests-table td.cell-right { display: none; }
+}
diff --git a/ui/packages/ci-dashboard/src/components/filters.js b/ui/packages/ci-dashboard/src/components/filters.js
new file mode 100644
index 00000000000..946f01d7c67
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/components/filters.js
@@ -0,0 +1,44 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+export function renderFilters(state, types) {
+ const typeButtons = types
+ .map((type) => {
+ const active = state.filterType === type;
+ const label = type === 'all' ? 'All Types' : type;
+ return `${label} `;
+ })
+ .join('');
+
+ const statuses = ['all', 'passed', 'failed', 'skipped'];
+ const statusButtons = statuses
+ .map((s) => {
+ const active = state.filterStatus === s;
+ const label = s === 'all' ? 'All' : s.charAt(0).toUpperCase() + s.slice(1);
+ const statusCls = s !== 'all' ? ` status-${s}` : '';
+ return `${label} `;
+ })
+ .join('');
+
+ return `
+
+
+
Type
+
${typeButtons}
+
+
+
+
Status
+
${statusButtons}
+
+
+ `;
+}
diff --git a/ui/packages/ci-dashboard/src/components/header.js b/ui/packages/ci-dashboard/src/components/header.js
new file mode 100644
index 00000000000..c8b7a9de36b
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/components/header.js
@@ -0,0 +1,63 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { escapeHtml, formatTimestamp } from '../utils/format.js';
+
+export function renderHeader(state) {
+ const run = state.runs[state.selectedRunIndex];
+ const sha = String(run.commit_sha ?? '').slice(0, 7);
+ const ts = formatTimestamp(run.timestamp);
+
+ const runOptions = state.runs
+ .map(
+ (r, i) =>
+ `
+ ${escapeHtml(r.release_version)} · ${escapeHtml(r.branch)}
+ `
+ )
+ .join('');
+
+ const controls =
+ state.runs.length > 1
+ ? `Run
+ ${runOptions} `
+ : `${escapeHtml(run.release_version)} `;
+
+ return `
+
+ `;
+}
diff --git a/ui/packages/ci-dashboard/src/components/job-table.js b/ui/packages/ci-dashboard/src/components/job-table.js
new file mode 100644
index 00000000000..a0ee882996a
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/components/job-table.js
@@ -0,0 +1,242 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { escapeHtml, statusBadge, typeBadge } from '../utils/format.js';
+
+function rateClass(rate) {
+ if (rate >= 95) return 'rate-fill-great';
+ if (rate >= 80) return 'rate-fill-good';
+ if (rate >= 60) return 'rate-fill-warn';
+ return 'rate-fill-bad';
+}
+
+/** Render the annotations panel (real test-failure data from check-run annotations). */
+function renderAnnotationsPanel(job, annotations, repo) {
+ const rows = annotations
+ .map((ann) => {
+ let fileHtml = '—';
+ if (ann.path) {
+ const encodedPath = encodeURIComponent(ann.path).replace(/%2F/g, '/');
+ const lineHash = ann.line ? `#L${ann.line}` : '';
+ if (repo) {
+ fileHtml = `${escapeHtml(ann.path)} `;
+ } else {
+ fileHtml = `${escapeHtml(ann.path)} `;
+ }
+ if (ann.line) {
+ fileHtml += `:${ann.line} `;
+ }
+ }
+ const messageHtml = ann.message
+ ? `
+ show details
+ ${escapeHtml(ann.message)}
+ `
+ : '— ';
+
+ return `
+
+
+
+ ${escapeHtml(ann.name)}
+
+ ${fileHtml}
+ ${messageHtml}
+ `;
+ })
+ .join('');
+
+ return `
+
+
+
+
+
+
+
+ Test
+ Location
+ Detail
+
+
+ ${rows}
+
+
+
+ `;
+}
+
+/** Render the step-cases panel (fallback when no annotation data is available). */
+function renderStepsPanel(job) {
+ const cases = (job.tests?.[0]?.cases ?? []);
+ if (cases.length === 0) return '';
+
+ const rows = cases
+ .map(
+ (c) => `
+
+
+
+ ${escapeHtml(c.name)}
+
+
+ ${statusBadge(c.status)}
+ ${c.duration_seconds ?? 0}s
+ `,
+ )
+ .join('');
+
+ return `
+
+
+
+
+
+
+ Step
+ Status
+ Duration
+
+
+ ${rows}
+
+
+
+ `;
+}
+
+export function renderJobTable(state, run) {
+ let jobs = run.jobs;
+
+ if (state.filterType !== 'all') {
+ jobs = jobs.filter((j) => j.type === state.filterType);
+ }
+ if (state.filterStatus !== 'all') {
+ jobs = jobs.filter((j) => j.status === state.filterStatus);
+ }
+
+ if (jobs.length === 0) {
+ return `
+
+
+
🔍
+
No jobs match these filters
+
Try changing the type or status filter above.
+
+ `;
+ }
+
+ const failedCount = jobs.filter((j) => j.status === 'failed').length;
+ const skippedCount = jobs.filter((j) => j.status === 'skipped').length;
+
+ const rows = jobs
+ .map((job) => {
+ const expanded = state.expandedJobId === job.job_id;
+ const rate = (job.stats?.pass_rate ?? 0).toFixed(0);
+ const barWidth = Math.max(0, Math.min(100, job.stats?.pass_rate ?? 0));
+ const statusRowClass = job.status === 'failed' ? ' row-failed' : job.status === 'skipped' ? ' row-skipped' : '';
+ const fillCls = rateClass(job.stats?.pass_rate ?? 0);
+
+ const annotations = job.annotations ?? [];
+ const stepCases = job.tests?.[0]?.cases ?? [];
+
+ // Annotation count badge shown in the job name column for failing jobs with test data.
+ const annotBadge = annotations.length > 0
+ ? `${annotations.length} test failure${annotations.length !== 1 ? 's' : ''} `
+ : '';
+
+ let expandedContent = '';
+ if (expanded) {
+ if (annotations.length > 0) {
+ expandedContent = renderAnnotationsPanel(job, annotations, run.repo);
+ } else if (stepCases.length > 0) {
+ expandedContent = renderStepsPanel(job);
+ } else {
+ expandedContent = `
+
+
+
+ No individual test breakdown available for this job.
+ ${job.status === 'failed' && run.summary?.annotations_fetched === false
+ ? ' Re-run aggregation without --skip-annotations to fetch test details. '
+ : ''}
+
+
+ `;
+ }
+ }
+
+ return `
+
+
+
+ ${expanded ? '▾' : '▸'}
+ ${escapeHtml(job.name)}
+ ${annotBadge}
+
+
+ ${typeBadge(job.type)}
+ ${statusBadge(job.status)}
+ ${job.stats?.passed ?? 0}
+ ${job.stats?.failed ?? 0}
+ ${job.stats?.skipped ?? 0}
+
+
+
+
+ ${expandedContent}
+ `;
+ })
+ .join('');
+
+ // Total test failures across all displayed jobs
+ const totalTestFailures = jobs.reduce((acc, j) => acc + (j.annotation_count ?? 0), 0);
+
+ const footerRight = failedCount > 0
+ ? `${failedCount} job${failedCount !== 1 ? 's' : ''} failed${totalTestFailures > 0 ? ` · ${totalTestFailures} test failure${totalTestFailures !== 1 ? 's' : ''}` : ''} `
+ : skippedCount > 0
+ ? `${skippedCount} skipped `
+ : `All passing ✓ `;
+
+ return `
+
+
+ Jobs
+ ${jobs.length} of ${run.jobs.length}
+
+
+
+
+ Job
+ Type
+ Status
+ Passed
+ Failed
+ Skipped
+ Pass Rate
+
+
+ ${rows}
+
+
+
+ `;
+}
+
diff --git a/ui/packages/ci-dashboard/src/components/summary-bar.js b/ui/packages/ci-dashboard/src/components/summary-bar.js
new file mode 100644
index 00000000000..7af079f4bbd
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/components/summary-bar.js
@@ -0,0 +1,83 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+export function renderSummaryBar(summary) {
+ const rate = (summary.pass_rate ?? 0).toFixed(1);
+ const rateNum = summary.pass_rate ?? 0;
+ const rateClass = rateNum >= 95 ? 'rate-great' : rateNum >= 80 ? 'rate-good' : rateNum >= 60 ? 'rate-warn' : 'rate-bad';
+
+ // SVG donut — r=40, circumference = 2π×40 ≈ 251.3
+ const CIRC = 251.3;
+ const fill = (rateNum / 100) * CIRC;
+ const gap = CIRC - fill;
+
+ return `
+
+
+
+
+
+
+
+
+ ${rate}%
+ Pass
+
+
+
+
+
+
+
+
+
+
+ ${summary.total_jobs}
+ Total Jobs
+
+
+ ${summary.passed}
+ Passed
+
+
+ ${summary.failed}
+ Failed
+
+
+ ${summary.skipped}
+ Skipped
+
+
+ ${summary.total_test_failures > 0
+ ? `${summary.total_test_failures}
+ Test Failures `
+ : `${summary.total_cases ?? summary.total_tests ?? '—'}
+ Cases `}
+
+
+
+ `;
+}
diff --git a/ui/packages/ci-dashboard/src/main.js b/ui/packages/ci-dashboard/src/main.js
new file mode 100644
index 00000000000..c12e839f7dc
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/main.js
@@ -0,0 +1,167 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import './app.css';
+import { renderHeader } from './components/header.js';
+import { renderSummaryBar } from './components/summary-bar.js';
+import { renderFilters } from './components/filters.js';
+import { renderJobTable } from './components/job-table.js';
+
+// ---------------------------------------------------------------------------
+// State
+// All mutable app state lives here. Components are pure render functions that
+// take state and return HTML strings. Mutations call render() to refresh.
+// ---------------------------------------------------------------------------
+const state = {
+ runs: [],
+ selectedRunIndex: 0,
+ filterType: 'all',
+ filterStatus: 'all',
+ expandedJobId: null,
+};
+
+function activeRun() {
+ return state.runs[state.selectedRunIndex];
+}
+
+function jobTypes(run) {
+ return ['all', ...new Set(run.jobs.map((j) => j.type).sort())];
+}
+
+// ---------------------------------------------------------------------------
+// Render
+// Rebuilds the entire app from state. Fast enough for ~100 jobs.
+// ---------------------------------------------------------------------------
+function render() {
+ const app = document.getElementById('app');
+ const run = activeRun();
+
+ app.innerHTML = `
+ ${renderHeader(state)}
+
+ ${renderSummaryBar(run.summary)}
+ ${renderFilters(state, jobTypes(run))}
+ ${renderJobTable(state, run)}
+
+ `;
+
+ attachListeners();
+}
+
+function attachListeners() {
+ // Run selector
+ document.getElementById('run-select')?.addEventListener('change', (e) => {
+ state.selectedRunIndex = parseInt(e.target.value, 10);
+ state.expandedJobId = null;
+ render();
+ });
+
+ // Type filter buttons
+ document.querySelectorAll('[data-filter-type]').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ state.filterType = btn.dataset.filterType;
+ state.expandedJobId = null;
+ render();
+ });
+ });
+
+ // Status filter buttons
+ document.querySelectorAll('[data-filter-status]').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ state.filterStatus = btn.dataset.filterStatus;
+ state.expandedJobId = null;
+ render();
+ });
+ });
+
+ // Job row expand / collapse (the tests-row is a sibling TR so clicks there
+ // do NOT bubble up to the job-row — no stopPropagation needed).
+ document.querySelectorAll('tr[data-job-id]').forEach((row) => {
+ row.addEventListener('click', () => {
+ const id = row.dataset.jobId;
+ state.expandedJobId = state.expandedJobId === id ? null : id;
+ render();
+ });
+ });
+}
+
+// ---------------------------------------------------------------------------
+// Bootstrap — fetch the data file dropped by CI into public/data/
+// ---------------------------------------------------------------------------
+async function init() {
+ const app = document.getElementById('app');
+ try {
+ const res = await fetch('./data/aggregated_ci_results.json');
+ if (!res.ok) throw new Error(`HTTP ${res.status} — ${res.statusText}`);
+
+ const payload = await res.json();
+ // Accept both a single run object and an array of runs
+ const runs = Array.isArray(payload) ? payload : [payload];
+ if (!runs.length) throw new Error('No run data found in the file.');
+
+ // Deduplicate jobs within each run by name — keep the highest-priority
+ // status (passed > failed > skipped) so that re-runs and shared setup
+ // steps that appear in multiple workflows don't inflate the counts.
+ const STATUS_RANK = { passed: 0, failed: 1, skipped: 2 };
+ for (const run of runs) {
+ const byName = new Map();
+ for (const job of run.jobs) {
+ const existing = byName.get(job.name);
+ if (!existing) {
+ byName.set(job.name, job);
+ } else {
+ const rank = (s) => STATUS_RANK[s] ?? 3;
+ if (rank(job.status) < rank(existing.status)) {
+ byName.set(job.name, job);
+ }
+ }
+ }
+ const dedupedJobs = [...byName.values()];
+ if (dedupedJobs.length !== run.jobs.length) {
+ console.log(`[dedup] ${run.release_version}: ${run.jobs.length} → ${dedupedJobs.length} jobs`);
+ run.jobs = dedupedJobs;
+ // Recompute summary counts to stay in sync with the deduplicated jobs.
+ const p = dedupedJobs.filter((j) => j.status === 'passed').length;
+ const f = dedupedJobs.filter((j) => j.status === 'failed').length;
+ const s = dedupedJobs.filter((j) => j.status === 'skipped').length;
+ const t = dedupedJobs.length;
+ run.summary = {
+ ...run.summary,
+ total_jobs: t,
+ total_tests: t,
+ passed: p,
+ failed: f,
+ skipped: s,
+ pass_rate: t > 0 ? parseFloat(((p / t) * 100).toFixed(1)) : 0,
+ };
+ }
+ }
+
+ state.runs = runs;
+ render();
+ } catch (err) {
+ app.innerHTML = `
+
+
⚠️
+
Could not load results
+
${escapeHtml(err.message)}
+
+ Drop aggregated_ci_results.json into
+ public/data/ and run pnpm dev.
+
+
+ `;
+ }
+}
+
+function escapeHtml(str) {
+ return String(str)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"');
+}
+
+init();
diff --git a/ui/packages/ci-dashboard/src/utils/format.js b/ui/packages/ci-dashboard/src/utils/format.js
new file mode 100644
index 00000000000..ca6b981fe3e
--- /dev/null
+++ b/ui/packages/ci-dashboard/src/utils/format.js
@@ -0,0 +1,41 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+// Shared utilities used by all components.
+
+const HTML_ESCAPE_MAP = { '&': '&', '<': '<', '>': '>', '"': '"' };
+
+export function escapeHtml(str) {
+ return String(str ?? '').replace(/[&<>"]/g, (c) => HTML_ESCAPE_MAP[c]);
+}
+
+export function statusBadge(status) {
+ const classes = {
+ passed: 'badge-passed',
+ failed: 'badge-failed',
+ skipped: 'badge-skipped',
+ };
+ const cls = classes[status] ?? 'badge-unknown';
+ return `${escapeHtml(status)} `;
+}
+
+export function typeBadge(type) {
+ const cls = `type-${escapeHtml(String(type).toLowerCase())}`;
+ return `${escapeHtml(type)} `;
+}
+
+export function formatTimestamp(iso) {
+ try {
+ return new Date(iso).toLocaleString(undefined, {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ } catch {
+ return iso;
+ }
+}
diff --git a/ui/packages/ci-dashboard/vite.config.js b/ui/packages/ci-dashboard/vite.config.js
new file mode 100644
index 00000000000..42d42bc9210
--- /dev/null
+++ b/ui/packages/ci-dashboard/vite.config.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright IBM Corp. 2024, 2026
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { defineConfig } from 'vite';
+
+// Base is './' so the built dist/ works whether served from root or a subdirectory
+// (e.g. GitHub Pages project page or any static host).
+export default defineConfig({
+ base: './',
+ build: {
+ outDir: 'dist',
+ emptyOutDir: true,
+ },
+});
diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml
index 1e796b89566..167b3fac6cc 100644
--- a/ui/pnpm-lock.yaml
+++ b/ui/pnpm-lock.yaml
@@ -68,6 +68,12 @@ importers:
specifier: ^4.1.5
version: 4.1.5
+ packages/ci-dashboard:
+ devDependencies:
+ vite:
+ specifier: ^5.4.0
+ version: 5.4.21(@types/node@24.5.2)(sass@1.89.2)(terser@5.31.1)
+
packages/consul-ui:
devDependencies:
'@babel/core':
@@ -1543,6 +1549,144 @@ packages:
'@glint/template':
optional: true
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint/eslintrc@0.4.3':
resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==}
engines: {node: ^10.12.0 || >=12.0.0}
@@ -1950,6 +2094,131 @@ packages:
'@ro0gr/ceibo@2.2.0':
resolution: {integrity: sha512-4gSXPwwr99zUWxnTllN5L4QlfgFDloYKOsenoPvx46LE75x3wvLgGUhxUxhIMxJbqOZ0w9pzrugjQR7St0/PQg==}
+ '@rollup/rollup-android-arm-eabi@4.60.4':
+ resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.60.4':
+ resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.60.4':
+ resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.60.4':
+ resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.60.4':
+ resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.60.4':
+ resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.60.4':
+ resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.60.4':
+ resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.60.4':
+ resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.60.4':
+ resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loong64-gnu@4.60.4':
+ resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loong64-musl@4.60.4':
+ resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.60.4':
+ resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-musl@4.60.4':
+ resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.60.4':
+ resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.60.4':
+ resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.60.4':
+ resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.60.4':
+ resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.60.4':
+ resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-openbsd-x64@4.60.4':
+ resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.60.4':
+ resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.60.4':
+ resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.60.4':
+ resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.60.4':
+ resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.60.4':
+ resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==}
+ cpu: [x64]
+ os: [win32]
+
'@simple-dom/document@1.4.0':
resolution: {integrity: sha512-/RUeVH4kuD3rzo5/91+h4Z1meLSLP66eXqpVAw/4aZmYozkeqUkMprq0znL4psX/adEed5cBgiNJcfMz/eKZLg==}
@@ -4125,6 +4394,11 @@ packages:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'}
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -6503,6 +6777,11 @@ packages:
engines: {node: '>=10.0.0'}
hasBin: true
+ rollup@4.60.4:
+ resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
route-recognizer@0.3.4:
resolution: {integrity: sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==}
@@ -7318,6 +7597,37 @@ packages:
vfile@4.2.1:
resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==}
+ vite@5.4.21:
+ resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
@@ -9085,6 +9395,75 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.21.5':
+ optional: true
+
'@eslint/eslintrc@0.4.3':
dependencies:
ajv: 6.14.0
@@ -9721,6 +10100,81 @@ snapshots:
'@ro0gr/ceibo@2.2.0': {}
+ '@rollup/rollup-android-arm-eabi@4.60.4':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.60.4':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.60.4':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.60.4':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.60.4':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.60.4':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.60.4':
+ optional: true
+
'@simple-dom/document@1.4.0':
dependencies:
'@simple-dom/interface': 1.4.0
@@ -12880,6 +13334,32 @@ snapshots:
is-date-object: 1.0.5
is-symbol: 1.0.4
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -15624,6 +16104,37 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ rollup@4.60.4:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.60.4
+ '@rollup/rollup-android-arm64': 4.60.4
+ '@rollup/rollup-darwin-arm64': 4.60.4
+ '@rollup/rollup-darwin-x64': 4.60.4
+ '@rollup/rollup-freebsd-arm64': 4.60.4
+ '@rollup/rollup-freebsd-x64': 4.60.4
+ '@rollup/rollup-linux-arm-gnueabihf': 4.60.4
+ '@rollup/rollup-linux-arm-musleabihf': 4.60.4
+ '@rollup/rollup-linux-arm64-gnu': 4.60.4
+ '@rollup/rollup-linux-arm64-musl': 4.60.4
+ '@rollup/rollup-linux-loong64-gnu': 4.60.4
+ '@rollup/rollup-linux-loong64-musl': 4.60.4
+ '@rollup/rollup-linux-ppc64-gnu': 4.60.4
+ '@rollup/rollup-linux-ppc64-musl': 4.60.4
+ '@rollup/rollup-linux-riscv64-gnu': 4.60.4
+ '@rollup/rollup-linux-riscv64-musl': 4.60.4
+ '@rollup/rollup-linux-s390x-gnu': 4.60.4
+ '@rollup/rollup-linux-x64-gnu': 4.60.4
+ '@rollup/rollup-linux-x64-musl': 4.60.4
+ '@rollup/rollup-openbsd-x64': 4.60.4
+ '@rollup/rollup-openharmony-arm64': 4.60.4
+ '@rollup/rollup-win32-arm64-msvc': 4.60.4
+ '@rollup/rollup-win32-ia32-msvc': 4.60.4
+ '@rollup/rollup-win32-x64-gnu': 4.60.4
+ '@rollup/rollup-win32-x64-msvc': 4.60.4
+ fsevents: 2.3.3
+
route-recognizer@0.3.4: {}
router@2.2.0:
@@ -16678,6 +17189,17 @@ snapshots:
unist-util-stringify-position: 2.0.3
vfile-message: 2.0.4
+ vite@5.4.21(@types/node@24.5.2)(sass@1.89.2)(terser@5.31.1):
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.5.12
+ rollup: 4.60.4
+ optionalDependencies:
+ '@types/node': 24.5.2
+ fsevents: 2.3.3
+ sass: 1.89.2
+ terser: 5.31.1
+
w3c-keyname@2.2.8: {}
walk-sync@0.2.7: