From 3e77634e1004b554a86af1649a44940f56c90baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Jeanneret?= Date: Mon, 5 Oct 2026 09:45:59 +0000 Subject: [PATCH] feat(ci): support GitHub badge sources Read optional ci_github_sources from pattern frontmatter and pass them through the pattern CI partial. Collect these sources for the main CI dashboard so GitHub results appear alongside existing bucket results. Fetch configured raw GitHub JSON files using the selected badge set. Reuse JSON metadata parsing for pattern, platform, version, and date; this preserves hyphenated pattern names without relying on filename splitting. Reuse fetched JSON during enrichment and skip unavailable GitHub files without dropping other results. Bucket discovery cannot list raw GitHub files. This adds that discovery path while keeping source configuration with its owning pattern and preserving existing bucket, preview, and time-range behavior. Assisted-by: Codex --- layouts/ci/single.html | 10 +++++++++- layouts/partials/ci.html | 2 +- static/js/dashboard.v2.js | 41 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/layouts/ci/single.html b/layouts/ci/single.html index d10c7244f0..af7b6ace7f 100644 --- a/layouts/ci/single.html +++ b/layouts/ci/single.html @@ -21,7 +21,15 @@

{{- .Title -}}

diff --git a/layouts/partials/ci.html b/layouts/partials/ci.html index aaad0b04b0..9d2bd9a5ff 100644 --- a/layouts/partials/ci.html +++ b/layouts/partials/ci.html @@ -5,6 +5,6 @@ {{ partial "spinner.html" . }} diff --git a/static/js/dashboard.v2.js b/static/js/dashboard.v2.js index 0b33a9cb4b..b6931062cc 100644 --- a/static/js/dashboard.v2.js +++ b/static/js/dashboard.v2.js @@ -4,17 +4,18 @@ class Badge { - constructor(base, key, date) { + constructor(base, key, date, useJsonMetadata = false) { this.base = base this.key = key this._json = null + this.useJsonMetadata = useJsonMetadata || isNewCiBadgeBase(base) this.operator = 'N/A' this.date = date.substr(0, 10) this.pattern = '' this.platform = '' this.version = '' - if (isNewCiBadgeBase(base)) { + if (this.useJsonMetadata) { return } @@ -36,7 +37,7 @@ class Badge { applyJson(json) { this._json = json - if (!isNewCiBadgeBase(this.base)) { + if (!this.useJsonMetadata) { return this } @@ -410,6 +411,9 @@ function enrichBadgesFromJson(badges) { return Promise.resolve(badges || []) } return Promise.all(badges.map(function (badge) { + if (badge._json != null) { + return Promise.resolve(badge) + } return fetch(badge.getURI()) .then(function (response) { if (!response.ok) { @@ -1401,6 +1405,34 @@ function fetchBucketBadges(bucket, inputs) { }) } +function fetchGithubBadges(source, badgeSet) { + const base = source.raw_base.replace(/\/$/, '') + const files = source.files.filter(function (key) { + return (badgeSet === 'GA' && key.endsWith('stable-badge.json')) || + (badgeSet === 'early' && (key.endsWith('prerelease-badge.json') || + key.endsWith('nightly-badge.json') || key.endsWith('operator-badge.json'))) || + (badgeSet === 'all' && key.endsWith('-badge.json')) + }) + return Promise.all(files.map(function (key) { + return fetch(base + '/' + key) + .then(function (response) { + if (!response.ok) { + throw new Error('HTTP error: ' + response.status) + } + return response.json() + }) + .then(function (json) { + return new Badge(base, key, json.date || '', true).applyJson(json) + }) + .catch(function (error) { + console.warn('GitHub CI badge unavailable:', key, error.message) + return null + }) + })).then(function (badges) { + return badges.filter(function (badge) { return badge != null }) + }) +} + function obtainBadgesFromSample(inputs) { const options = getBucketOptions(inputs); @@ -1440,6 +1472,9 @@ function obtainBadges(inputs) { for (const bucket of buckets) { badgePromises.push(fetchBucketBadges(bucket, inputs)); } + for (const source of inputs.github_sources || []) { + badgePromises.push(fetchGithubBadges(source, options.get('sets'))) + } Promise.all(badgePromises) .then(function (results) {