|
| 1 | +# urunc CI Dashboard |
| 2 | + |
| 3 | +A real-time dashboard for monitoring urunc CI test status. |
| 4 | + |
| 5 | +**Live Dashboard**: https://urunc-dev.github.io/ci-dashboard/ |
| 6 | + |
| 7 | +## Features |
| 8 | + |
| 9 | +### Dashboard UI |
| 10 | + |
| 11 | +- **Dual-period stats** — separate stat cards for the last 24 hours and all-time totals (success rate, runs executed, passed, failed) |
| 12 | +- **Workflow table** — sortable by name, last run conclusion, success rate, avg duration, and weather history |
| 13 | +- **7-run weather history** — colored dots showing the last 7 run outcomes at a glance (oldest → newest) |
| 14 | +- **Filter chips** — instantly filter by: All, Failing, Passing, Critical, Recent Failure, Recent Run, No Runs |
| 15 | +- **Expandable drawer** — click any workflow row to reveal: |
| 16 | + - **Runs table** — all recent runs with conclusion, date, duration, attempt number, and direct GitHub link |
| 17 | + - **Structured log viewer** — failure signals grouped by category with keyword highlighting |
| 18 | + - **Per-workflow charts** — avg job duration, pass/fail per run, duration trend |
| 19 | +- **Overview charts panel** — activated via the Charts chip: |
| 20 | + - Overall passed vs failed |
| 21 | + - Avg duration per workflow |
| 22 | + - Execution time last 7 runs per workflow |
| 23 | + - Success rate by workflow |
| 24 | + - **Auto-refresh indicator** — Data updates every cronjob run |
| 25 | +---------- |
| 26 | + |
| 27 | +## Architecture |
| 28 | + |
| 29 | +``` |
| 30 | +┌──────────────────────────────────────────────────────────────────────────┐ |
| 31 | +│ Config layer — config.yaml │ |
| 32 | +│ ├── settings repo, run limits │ |
| 33 | +│ ├── log_analysis noise_patterns, failure categories + priority │ |
| 34 | +│ ├── notify enabled, target_repo, label │ |
| 35 | +│ └── workflows name, description, critical flag │ |
| 36 | +└──────────────────────┬───────────────────────────────────────────────────┘ |
| 37 | + │ loads |
| 38 | +┌──────────────────────▼───────────────────────────────────────────────────┐ |
| 39 | +│ Log analysis pipeline — main.go │ |
| 40 | +│ │ |
| 41 | +│ GH Actions client ──► Stage 1: noise gate ──► Stage 2: category match │ |
| 42 | +│ (workflows_raw.json matchesAny() strips priority sort │ |
| 43 | +│ runs_raw.json) noise_patterns → LogSummary │ |
| 44 | +│ │ ▲ │ │ |
| 45 | +│ │ failed runs │ raw log lines │ LogSnippet │ |
| 46 | +│ ▼ │ ▼ │ |
| 47 | +│ fetchJobsAndEnrich() ─────────┘ renderSummary() │ |
| 48 | +│ │ │ │ |
| 49 | +│ └──────────────► buildSummary() ◄────────────┘ │ |
| 50 | +│ WeatherHistory, WorkflowSummary │ |
| 51 | +│ │ writes │ |
| 52 | +│ stats.json │ |
| 53 | +└──────────────────────┬─────────┴────────────────────────────────────────┘ |
| 54 | + │ WorkflowSummary (critical workflows only) |
| 55 | +┌──────────────────────▼───────────────────────────────────────────────────┐ |
| 56 | +│ Notification engine — notify.go │ |
| 57 | +│ │ |
| 58 | +│ Notifier.Process() │ |
| 59 | +│ critical=true + anyFailed()? │ |
| 60 | +│ │ └──── no ──► Skip │ |
| 61 | +│ ▼ │ |
| 62 | +│ findOpenIssue() (paginated title match) │ |
| 63 | +│ / \ │ |
| 64 | +│ no issue exists + 24 h passed │ |
| 65 | +│ │ │ │ |
| 66 | +│ createIssue() addComment() │ |
| 67 | +└──────────────────────────────────────────────────────────────────────────┘ |
| 68 | + │ |
| 69 | + stats.json |
| 70 | + │ |
| 71 | +┌──────────────────────▼───────────────────────────────────────────────────┐ |
| 72 | +│ Frontend — index.html + styles.css + script.js │ |
| 73 | +│ reads stats.json → renders dashboard │ |
| 74 | +│ Chart.js 2.9 — pie, doughnut, bar, line charts │ |
| 75 | +└──────────────────────────────────────────────────────────────────────────┘ |
| 76 | +
|
| 77 | +``` |
| 78 | + |
| 79 | +## Repository Layout |
| 80 | + |
| 81 | +``` |
| 82 | +. |
| 83 | +├── .github/ |
| 84 | +│ └── workflows/ |
| 85 | +│ └── update-stats.yml # Cronjob, commits stats.json |
| 86 | +├── main.go # Data fetching, log analysis, stats generation |
| 87 | +├── notify.go # GitHub issue/comment notification engine |
| 88 | +├── config.yaml # All configuration |
| 89 | +├── index.html # Dashboard markup |
| 90 | +├── styles.css # Dark/light theme, table, chart, log viewer styles |
| 91 | +├── script.js # Dashboard logic — filters, charts, drawer, log renderer |
| 92 | +└── stats.json # Auto-generated by cronjob |
| 93 | +``` |
| 94 | + |
| 95 | +---------- |
| 96 | + |
| 97 | +## Configuration |
| 98 | + |
| 99 | +All configuration lives in `config.yaml`. |
| 100 | + |
| 101 | +### Settings |
| 102 | + |
| 103 | +```yaml |
| 104 | +settings: |
| 105 | + source_repo: "urunc-dev/urunc" # Repo to monitor |
| 106 | + max_runs_per_workflow: 40 # Runs to fetch per workflow |
| 107 | + recent_runs_in_output: 40 # Runs included in stats.json |
| 108 | +``` |
| 109 | +### Notifications |
| 110 | +
|
| 111 | +```yaml |
| 112 | +notify: |
| 113 | + enabled: true |
| 114 | + target_repo: "your-org/your-repo" # Where issues are opened |
| 115 | + label: "ci-failure" # Label applied to opened issues |
| 116 | +``` |
| 117 | +
|
| 118 | +### Log analysis |
| 119 | +
|
| 120 | +```yaml |
| 121 | +log_analysis: |
| 122 | + max_signals_per_job: 40 |
| 123 | + |
| 124 | + noise_patterns: # Lines matching these are dropped before analysis |
| 125 | + - "sudo process started" |
| 126 | + - "/usr/lib/gcc/" |
| 127 | + |
| 128 | + categories: # Lower priority number = more important |
| 129 | + - name: "Crash / Timeout" |
| 130 | + priority: 1 |
| 131 | + patterns: ["panic:", "test timed out", "deadlock"] |
| 132 | + |
| 133 | + - name: "Network Failure" |
| 134 | + priority: 2 |
| 135 | + patterns: ["connection reset by peer", "i/o timeout"] |
| 136 | + |
| 137 | + - name: "Test Failure" |
| 138 | + priority: 3 |
| 139 | + patterns: ["--- fail:", "expected", "received"] |
| 140 | + |
| 141 | + - name: "Build Failure" |
| 142 | + priority: 4 |
| 143 | + patterns: ["make: ***", "##[error]", "compilation terminated"] |
| 144 | + |
| 145 | + - name: "Fatal Runtime Error" |
| 146 | + priority: 5 |
| 147 | + patterns: ["level=fatal", "fatal: "] |
| 148 | +``` |
| 149 | +
|
| 150 | +The frontend log viewer maps these category names to colored badges automatically (`Crash / Timeout` → red, `Network Failure` → blue, `Test Failure` → orange, `Build Failure` → purple, `Fatal Runtime Error` → red). |
| 151 | + |
| 152 | +### Workflows |
| 153 | + |
| 154 | +```yaml |
| 155 | +workflows: |
| 156 | + - name: "ci" |
| 157 | + description: "Main CI workflow" |
| 158 | + critical: true # critical=true workflows trigger issue notifications |
| 159 | + # and show a red "critical" badge in the dashboard |
| 160 | + - name: "scorecard" |
| 161 | + description: "Security scorecard" |
| 162 | + critical: false # monitored in dashboard, no issue opened on failure |
| 163 | +``` |
| 164 | +---------- |
| 165 | + |
| 166 | +## How It Works |
| 167 | + |
| 168 | +1. **Github cronjob** fetches `workflows_raw.json` and `runs_raw.json` from the GitHub API using `gh CLI`, then progress with go app. |
| 169 | +2. For each configured workflow, the Go pipeline: |
| 170 | + - Fetches job-level data for recent runs |
| 171 | + - For failed jobs, downloads and time-windows the raw log, strips noise, categorises signals by priority |
| 172 | + - Falls back to check-run annotations if the log has expired |
| 173 | + - Builds a `WorkflowSummary` with weather history, failure rate, avg duration, and log snippets |
| 174 | +3. Writes `stats.json` and commits it back to the repo |
| 175 | +4. For each `critical: true` workflow with a recent failure, the notifier opens or updates a GitHub issue |
| 176 | +5. GitHub Pages serves `index.html` which fetches `stats.json` and renders the dashboard |
| 177 | +---------- |
| 178 | + |
| 179 | + |
| 180 | +## Local Development |
| 181 | + |
| 182 | +```bash |
| 183 | +# Fetch raw data (requires gh CLI and GITHUB_TOKEN in environment) |
| 184 | +export GITHUB_TOKEN=your_token |
| 185 | +
|
| 186 | +gh api repos/urunc-dev/urunc/actions/workflows \ |
| 187 | + --paginate > workflows_raw.json |
| 188 | +
|
| 189 | +# Fetch runs for a specific workflow ID |
| 190 | +gh api "repos/urunc-dev/urunc/actions/workflows/<id>/runs?per_page=40" \ |
| 191 | + > runs_raw.json |
| 192 | +
|
| 193 | +# Run the pipeline |
| 194 | +go run . |
| 195 | +
|
| 196 | +# Preview the dashboard |
| 197 | +python3 -m http.server 8080 |
| 198 | +open http://localhost:8080 |
| 199 | +``` |
| 200 | +---------- |
| 201 | + |
| 202 | + |
| 203 | +## Contributing |
| 204 | + |
| 205 | +1. **Add new tests/modify failure/notify**: Edit `config.yaml` and add desirable configurations |
| 206 | +2. **UI changes**: Modify `index.html`, `style.css`, or `app.js` |
| 207 | +3. **Cronjob data processing**: Modify `github/workflows/updates.yaml` |
| 208 | + |
| 209 | +---------- |
| 210 | + |
| 211 | +## License |
| 212 | + |
| 213 | +Apache 2.0 - See [LICENSE](LICENSE) |
0 commit comments