Skip to content

Commit c35560f

Browse files
committed
generate dashboard
1 parent eb86abc commit c35560f

2 files changed

Lines changed: 100 additions & 51 deletions

File tree

.github/workflows/ci.yml

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -68,58 +68,28 @@ jobs:
6868
path: badge-status/status-${{ matrix.os }}-${{ matrix.compiler }}.json
6969
overwrite: true
7070

71-
generate-badges:
72-
name: Generate SVG Badges
73-
runs-on: ubuntu-latest
74-
needs: build
75-
if: always()
71+
generate-dashboard:
72+
name: Generate unified dashboard
73+
runs-on: ubuntu-latest
74+
needs: build
75+
if: always()
7676

77-
steps:
78-
- uses: actions/checkout@v4
79-
80-
- name: Determine badge target directory
81-
id: badge_dir
82-
run: |
83-
if [[ "${GITHUB_REF##*/}" == "staging" ]]; then
84-
echo "dir=badges-staging" >> $GITHUB_OUTPUT
85-
else
86-
echo "dir=badges" >> $GITHUB_OUTPUT
87-
fi
88-
89-
- name: Download all badge status artifacts
90-
uses: actions/download-artifact@v4
91-
with:
92-
path: badge-status
93-
pattern: status-*
94-
merge-multiple: true
95-
96-
- name: Generate SVG Badges
97-
run: |
98-
mkdir -p ${{ steps.badge_dir.outputs.dir }}
99-
for f in badge-status/*.json; do
100-
echo "file name: $f"
101-
[[ ! -f "$f" ]] && continue
102-
os=$(jq -r .os "$f")
103-
compiler=$(jq -r .compiler "$f")
104-
status=$(jq -r .status "$f")
105-
106-
color="gray"
107-
symbol="□"
108-
109-
[[ "$status" == "success" ]] && { symbol="✔"; color="green"; }
110-
[[ "$status" == "skipped" ]] && { symbol="○"; color="gray"; }
111-
[[ "$status" == "failure" ]] && { symbol="✘"; color="red"; }
77+
steps:
78+
- uses: actions/checkout@v4
11279

113-
label="${os}-${compiler}"
114-
badge="${{ steps.badge_dir.outputs.dir }}/${label}.svg"
115-
echo "https://img.shields.io/badge/${prefix}-${symbol}-${color}.svg $badge"
116-
curl -s "https://img.shields.io/badge/${prefix}-${symbol}-${color}.svg" -o "$badge"
117-
done
80+
- name: Download all badge status artifacts
81+
uses: actions/download-artifact@v4
82+
with:
83+
path: badge-status
84+
pattern: status-*
85+
merge-multiple: true
11886

119-
- name: Upload badge folder to GitHub Pages
120-
uses: peaceiris/actions-gh-pages@v3
121-
with:
122-
github_token: ${{ secrets.GITHUB_TOKEN }}
123-
publish_dir: ./${{ steps.badge_dir.outputs.dir }}
124-
destination_dir: ${{ steps.badge_dir.outputs.dir }}
87+
- name: Generate unified dashboard
88+
run: python3 scripts/ci-generate-dashboard.py
12589

90+
- name: Upload dashboard to GitHub Pages
91+
uses: peaceiris/actions-gh-pages@v3
92+
with:
93+
github_token: ${{ secrets.GITHUB_TOKEN }}
94+
publish_dir: ./
95+
destination_dir: badges

scripts/ci-generate-dashboard.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
import json
3+
import glob
4+
from pathlib import Path
5+
6+
# Collect all status JSON files
7+
status_files = glob.glob("badge-status/status-*.json")
8+
9+
matrix = {}
10+
oses, compilers = set(), set()
11+
12+
for f in status_files:
13+
with open(f) as fh:
14+
data = json.load(fh)
15+
os = data["os"]
16+
compiler = data["compiler"]
17+
status = data["status"]
18+
matrix[(os, compiler)] = status
19+
oses.add(os)
20+
compilers.add(compiler)
21+
22+
# Sort for consistent layout
23+
oses = sorted(oses)
24+
compilers = sorted(compilers)
25+
26+
# SVG layout parameters
27+
cell_w, cell_h = 60, 40
28+
header_h = 100
29+
row_label_w = 150
30+
svg_w = row_label_w + len(compilers) * cell_w + 50
31+
svg_h = header_h + len(oses) * cell_h + 50
32+
33+
def status_color_symbol(status):
34+
if status == "success":
35+
return "green", "✔"
36+
elif status == "failure":
37+
return "red", "✘"
38+
else: # default: skipped or missing
39+
return "gray", "○"
40+
41+
# Start SVG
42+
svg = [
43+
f'<svg xmlns="http://www.w3.org/2000/svg" width="{svg_w}" height="{svg_h}" font-family="monospace">'
44+
]
45+
46+
# Column headers (rotated -45° for readability)
47+
for j, comp in enumerate(compilers):
48+
x = row_label_w + j * cell_w + cell_w // 2
49+
y = header_h - 30
50+
svg.append(
51+
f'<text x="{x}" y="{y}" transform="rotate(-45,{x},{y})" font-size="12">{comp}</text>'
52+
)
53+
54+
# Row headers
55+
for i, os in enumerate(oses):
56+
y = header_h + i * cell_h + cell_h // 2 + 5
57+
svg.append(f'<text x="10" y="{y}" font-size="14">{os}</text>')
58+
59+
# Grid cells
60+
for i, os in enumerate(oses):
61+
for j, comp in enumerate(compilers):
62+
status = matrix.get((os, comp), "skipped")
63+
color, symbol = status_color_symbol(status)
64+
x = row_label_w + j * cell_w
65+
y = header_h + i * cell_h
66+
svg.append(
67+
f'<rect x="{x}" y="{y}" width="{cell_w}" height="{cell_h}" '
68+
f'fill="{color}" fill-opacity="0.3" stroke="black"/>'
69+
)
70+
svg.append(
71+
f'<text x="{x + cell_w/2}" y="{y + cell_h/2 + 5}" '
72+
f'text-anchor="middle" font-size="18">{symbol}</text>'
73+
)
74+
75+
svg.append("</svg>")
76+
77+
# Write output
78+
Path("dashboard.svg").write_text("\n".join(svg))
79+
print("✅ Generated dashboard.svg")

0 commit comments

Comments
 (0)