Skip to content

Commit 8cac497

Browse files
feat: refactor CI status flow and failed-job log handling (#2)
* feat: refactor ci status flow and failed-job logs * fix: address review feedback and tighten repo parsing
1 parent 16f1672 commit 8cac497

10 files changed

Lines changed: 608 additions & 664 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 364 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ octocrab = "0.49"
1212
serde = { version = "1", features = ["derive"] }
1313
serde_json = "1"
1414
tokio = { version = "1", features = ["full"] }
15-
zip = "2"
15+
http-body-util = "0.1"

README.md

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,111 @@
11
# Run
22

33
- Set the `GITHUB_TOKEN` environment variable.
4+
- Optional: set `LLM=true` for concise CI output.
45
- Run `cargo build`, then execute the tool inside a git repository whose CI status you want to check.
56

67
# Features
78

89
1. Fetches CI status from GitHub Actions.
910
2. Displays the status of all workflows (success/failure).
10-
3. Saves a detailed report to a local file.
11+
3. Saves CI report files to local output.
12+
4. Downloads logs for failed jobs only (instead of all jobs in a failed workflow run).
13+
14+
# Project structure
15+
16+
```text
17+
gh-ci-tool/
18+
|-- src/
19+
| |-- main.rs # orchestrates CI fetch/report/log workflow
20+
| |-- args.rs # CLI arguments
21+
| |-- models.rs # CI workflow/job data models + status helpers
22+
| |-- output.rs # output mode/profile (llm vs human)
23+
| |-- report.rs # human + llm report rendering
24+
| |-- logs.rs # job log download helpers
25+
| |-- repo.rs # git branch/commit/repo parsing helpers
26+
|-- Cargo.toml
27+
|-- README.md
28+
```
1129

1230
Log locations:
1331

14-
- CI status JSON: `.gh-ci-tool/<commit>/ci-status.json`
15-
- CI status report: `.gh-ci-tool/<commit>/ci-status.txt`
16-
- Failed workflow logs (if any): `.gh-ci-tool/<commit>/logs/<workflow name>-<run id>/`
32+
- CI status JSON (compact, no pretty formatting): `.gh-ci-tool/<commit>/ci-status.json`
33+
- CI status report (human): `.gh-ci-tool/<commit>/ci-status.txt`
34+
- LLM concise report (LLM): `.gh-ci-tool/<commit>/ci-status.llm.txt`
35+
- Failed job logs (if any): `.gh-ci-tool/<commit>/logs/<workflow name (sanitized)>-<run id>/<job name (sanitized)>-<job id>.log`
36+
- LLM compact log summaries (when `LLM=true`): `.gh-ci-tool/<commit>/logs/<workflow name (sanitized)>-<run id>/<job name (sanitized)>-<job id>.log.llm.txt`
37+
38+
Path components are sanitized by `sanitize_path_component` (`[A-Za-z0-9_.]` kept, other chars replaced by `-`, duplicate/trailing `-` collapsed/trimmed).
1739

1840
```console
19-
Current branch: autoupdate-libjxl-v0.11.2
20-
Latest commit: 7f25db0b89eff104d54124cecf597b13966c1c81
41+
Current branch: autoupdate-librats-0.8.0
42+
Latest commit: 64b9e2ebc1aad19c854e9510d3d2b9bd62db7ed6
2143
Repository: xmake-io/xmake-repo
22-
Fetching current branch workflows...
23-
⠉ [00:00:01] 2/17 Fetching FreeBSD jobs - Windows (arm64) ✔
24-
- macOS (x86_64) ✔
25-
- Linux (arm64) ✔
26-
- iPhoneOS ✔
27-
- macOS (arm64) ✔
28-
- Archlinux ✔
29-
- Wasm (Ubuntu) ❌
30-
- build (ubuntu-latest, shared): Cancelled
31-
- build (ubuntu-latest, static): Failure
32-
- FreeBSD ❌
33-
- build (ubuntu-latest, shared): Cancelled
34-
- build (ubuntu-latest, static): Failure
35-
- Android (Windows) ✔
36-
- MingW (Msys2) ✔
37-
- MingW (MacOS) ✔
38-
- Linux ✔
39-
- Linux (Clang) ✔
40-
- Fedora ✔
41-
- Cross ✔
42-
- Windows ✔
43-
- Android ✔
44-
Logs extracted to .gh-ci-tool\7f25db0b\logs\Wasm-(Ubuntu)-22009069016
45-
Logs extracted to .gh-ci-tool\7f25db0b\logs\FreeBSD-22009069021
44+
- Linux ❌
45+
- build (ubuntu-latest, static, debug): Failure
46+
- build (ubuntu-latest, shared, release): Cancelled
47+
- build (ubuntu-latest, static, release): Cancelled
48+
- build (ubuntu-latest, shared, debug): Cancelled
49+
- Windows (arm64) ✅
50+
- MingW (Msys2) ✅
51+
- Windows ❌
52+
- build (windows-2025, static, x64, MD): Failure
53+
- build (windows-2025, static, x64, MT): Failure
54+
- build (windows-2025, static, arm64, MT): Success
55+
- build (windows-2025, static, x86, MT): Failure
56+
- build (windows-2025, shared, x64, MT): Failure
57+
- build (windows-2025, shared, x86, MT): Failure
58+
- build (windows-2025, shared, x64, MD): Failure
59+
- build (windows-2025, static, x86, MD): Failure
60+
- build (windows-2025, static, arm64, MD): Success
61+
- build (windows-2025, shared, x86, MD): Failure
62+
- build (windows-2025, shared, arm64, MT): Success
63+
- build (windows-2025, shared, arm64, MD): Success
64+
- iPhoneOS ✅
65+
- Cross ❌
66+
- build (ubuntu-latest, aarch64-none-linux-gnu): Cancelled
67+
- build (ubuntu-latest, arm-none-linux-gnueabihf): Failure
68+
- Linux (Clang) ❌
69+
- build (ubuntu-latest, static): Cancelled
70+
- build (ubuntu-latest, shared): Failure
71+
- Linux (arm64) ❌
72+
- build (ubuntu-24.04-arm, static, debug): Cancelled
73+
- build (ubuntu-24.04-arm, shared, release): Failure
74+
- build (ubuntu-24.04-arm, shared, debug): Cancelled
75+
- build (ubuntu-24.04-arm, static, release): Cancelled
76+
- Fedora ❌
77+
- build (ubuntu-latest, shared): Failure
78+
- build (ubuntu-latest, static): Cancelled
79+
- MingW (MacOS) ✅
80+
- Archlinux ❌
81+
- build (ubuntu-latest, shared): Failure
82+
- build (ubuntu-latest, static): Cancelled
83+
- macOS (x86_64) ❌
84+
- build (macos-15-intel, x86_64, static): Failure
85+
- build (macos-15-intel, x86_64, shared): Failure
86+
- macOS (arm64) ❌
87+
- build (macos-14, arm64, shared): Failure
88+
- build (macos-14, arm64, static): Failure
89+
- Android ✅
90+
- Android (Windows) ✅
91+
- Wasm (Ubuntu) ✅
92+
- FreeBSD ✅
93+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Linux-22424544319\build-ubuntu-latest-static-debug-64929684784.log
94+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-static-x64-MD-64929684843.log
95+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-static-x64-MT-64929684875.log
96+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-static-x86-MT-64929684877.log
97+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-shared-x64-MT-64929684904.log
98+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-shared-x86-MT-64929684905.log
99+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-shared-x64-MD-64929684907.log
100+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-static-x86-MD-64929684912.log
101+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Windows-22424544326\build-windows-2025-shared-x86-MD-64929684914.log
102+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Cross-22424544346\build-ubuntu-latest-arm-none-linux-gnueabihf-64929684705.log
103+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Linux-Clang-22424544318\build-ubuntu-latest-shared-64929684722.log
104+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Linux-arm64-22424544338\build-ubuntu-24.04-arm-shared-release-64929684766.log
105+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Fedora-22424544332\build-ubuntu-latest-shared-64929684707.log
106+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\Archlinux-22424544342\build-ubuntu-latest-shared-64929684814.log
107+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\macOS-x86_64-22424544328\build-macos-15-intel-x86_64-static-64929684704.log
108+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\macOS-x86_64-22424544328\build-macos-15-intel-x86_64-shared-64929684721.log
109+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\macOS-arm64-22424544315\build-macos-14-arm64-shared-64929684665.log
110+
Failed job log saved to .gh-ci-tool\64b9e2eb\logs\macOS-arm64-22424544315\build-macos-14-arm64-static-64929684668.log```
46111
```

src/args.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use clap::Parser;
2+
3+
#[derive(Parser, Debug)]
4+
#[command(name = "gh-ci-tool")]
5+
#[command(about = "Check GitHub Actions CI status for current commit")]
6+
pub struct Args {
7+
/// Disable log download for failed jobs
8+
#[arg(long, default_value_t = false)]
9+
pub no_logs: bool,
10+
}

src/logs.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use anyhow::{Context, Result};
2+
use http_body_util::BodyExt;
3+
use octocrab::Octocrab;
4+
5+
pub fn sanitize_path_component(name: &str) -> String {
6+
let mut out = String::with_capacity(name.len());
7+
let mut last_dash = false;
8+
9+
for ch in name.chars() {
10+
let mapped = if ch.is_ascii_alphanumeric() || ch == '_' || ch == '.' {
11+
ch
12+
} else {
13+
'-'
14+
};
15+
16+
if mapped == '-' {
17+
if !last_dash {
18+
out.push('-');
19+
last_dash = true;
20+
}
21+
} else {
22+
out.push(mapped);
23+
last_dash = false;
24+
}
25+
}
26+
27+
let trimmed = out.trim_matches('-');
28+
if trimmed.is_empty() {
29+
"unknown".to_string()
30+
} else {
31+
trimmed.to_string()
32+
}
33+
}
34+
35+
pub async fn download_job_log(
36+
octocrab: &Octocrab,
37+
owner: &str,
38+
repo: &str,
39+
job_id: u64,
40+
) -> Result<Vec<u8>> {
41+
let route = format!("/repos/{owner}/{repo}/actions/jobs/{job_id}/logs");
42+
let response = octocrab
43+
._get(route)
44+
.await
45+
.with_context(|| format!("Failed to request logs for job {}", job_id))?;
46+
let response = octocrab
47+
.follow_location_to_data(response)
48+
.await
49+
.with_context(|| format!("Failed to follow logs redirect for job {}", job_id))?;
50+
let bytes = response
51+
.into_body()
52+
.collect()
53+
.await
54+
.with_context(|| format!("Failed to download logs body for job {}", job_id))?
55+
.to_bytes();
56+
Ok(bytes.to_vec())
57+
}

0 commit comments

Comments
 (0)