feat(atlas): per-job CI status + build-injected version in the UI
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 18s
CD / Deploy via GitOps (push) Has been skipped

Phase C: the CI stage now shows the latest run's per-JOB status (Lint/Test,
Build, Deploy, …), each coloured by outcome, from the Gitea /actions/tasks
per-job entries — replacing the static cd.yml job-id list when live.
LatestRunJobs/RunNodes + RunSummary.State aggregate, all test-first.

Version: injected at build via -ldflags from `git describe --tags` (CI checkout
now fetch-depth:0 + --build-arg), served in /api/atlas.json, shown in the header.
No more hand-maintained version label drifting from the git tag.

Verified: build/vet/lint(0)/test green; version ldflag served correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 07:21:52 +02:00
co-authored by Claude Opus 4.8
parent 02a23a02dd
commit 3ff922a4d5
9 changed files with 159 additions and 88 deletions
+6 -4
View File
@@ -11,6 +11,7 @@ import (
"git.d-ma.be/mathias/cad-atlas/internal/atlas"
"git.d-ma.be/mathias/cad-atlas/internal/cluster"
"git.d-ma.be/mathias/cad-atlas/internal/gitea"
"git.d-ma.be/mathias/cad-atlas/internal/version"
)
// atlasHTML is the Phase-A/B static shell. It fetches /api/atlas.json at load
@@ -38,6 +39,7 @@ func NewHandler() http.Handler {
http.Error(w, "atlas build failed", http.StatusInternalServerError)
return
}
a.Version = version.Value
ld := liveOverlay()
if len(ld.hosts) > 0 {
a.Substrate = atlas.MergeSubstrate(a.Substrate, ld.hosts)
@@ -46,10 +48,10 @@ func NewHandler() http.Handler {
a.NS = "Tailscale mesh · " + ld.ns
}
if ld.run != nil {
node := atlas.RunNode(*ld.run)
nodes := atlas.RunNodes(*ld.run)
for i := range a.Stages {
if a.Stages[i].Generate == "ci-jobs" {
a.Stages[i].Nodes = append([]atlas.Node{node}, a.Stages[i].Nodes...)
a.Stages[i].Nodes = nodes
}
}
}
@@ -63,7 +65,7 @@ func NewHandler() http.Handler {
type liveOverlayData struct {
hosts []atlas.Host
ns string
run *atlas.Run
run *atlas.RunSummary
}
// live cache: query the cluster at most once per TTL; fall back to the authored
@@ -96,7 +98,7 @@ func liveOverlay() liveOverlayData {
}
}
if raw, err := gitea.Runs(); err == nil {
if r, err := atlas.LatestRun(raw); err == nil {
if r, err := atlas.LatestRunJobs(raw); err == nil {
d.run = &r
}
}