package atlas import ( "encoding/json" "fmt" ) // Run is one Gitea Actions workflow run — a real execution of the pipeline. type Run struct { Number int `json:"run_number"` Status string `json:"status"` Conclusion string `json:"conclusion"` SHA string `json:"head_sha"` Title string `json:"display_title"` URL string `json:"url"` } // State is the effective outcome: the conclusion if set, else the status. func (r Run) State() string { if r.Conclusion != "" { return r.Conclusion } return r.Status } // RunNode renders a run as a stage node, coloured by outcome // (success=green, failure/cancelled=coral, otherwise amber/in-progress). func RunNode(r Run) Node { pill := "var(--amber)" switch r.State() { case "success": pill = "var(--green)" case "failure", "cancelled": pill = "var(--coral)" } sha := r.SHA if len(sha) > 7 { sha = sha[:7] } return Node{ Title: fmt.Sprintf("▶ run #%d · %s", r.Number, r.State()), Desc: r.Title, Pill: pill, Tags: []string{"live · Gitea Actions", sha}, } } // LatestRun parses a Gitea `/actions/tasks` response and returns the newest run. func LatestRun(tasksJSON []byte) (Run, error) { var resp struct { Runs []Run `json:"workflow_runs"` } if err := json.Unmarshal(tasksJSON, &resp); err != nil { return Run{}, fmt.Errorf("parse runs: %w", err) } if len(resp.Runs) == 0 { return Run{}, fmt.Errorf("no workflow runs") } return resp.Runs[0], nil }