OXYGENHUB

No failed scheduled run every minute for a pipeline that does not parse 5f3fa151688e

A scheduled tick cannot tell whether a pipeline it cannot read has a
schedule, so it starts nothing; the push's run already reports the
problem. oxygenhub-android had about 1,500 such runs.

closes #321
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-26 00:48 UTC
Signature
◈ sealed by Andy McCall
Hash
5f3fa151688e8b1d91d5cd3dfe316416683c13a6d1244fc1ea4859dce74b4e99
Depends on
1edac4b68c6d 348f8c4baccf 42fa95540468 a7e6e8e6094c b5668108487f c889911bec12 d2263e299da7
Depended on by
f87a74fffc87 c2efc0b4674d
In bookmarks
api-unknown-fields diffusion-pin-bookmark main proposal-list-fast
In tags
v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
Edits
3 atoms, 0 tree operations, 3 files

Browse the tree at this change

modified CHANGELOG.md +1 −0
…
3 unchanged lines
4 4
5 5
## Unreleased
6 6
7 +
- **No failed run every minute for a pipeline that does not parse (#321):** the scheduler asked each repository's pipeline every minute and, for one it could not read (a mistake, or no jobs yet), recorded a failed `schedule` run each time: oxygenhub-android had about 1,500. A scheduled tick now starts nothing for such a pipeline; its push's run still says what is wrong.
7 8
- **A change's diff through the API (#320):** `GET /api/v1/repos/{owner}/{name}/changes/{hash}` gives each file's diff lines too (`lines`: `kind` context, add, del or gap, `old` and `new` line numbers, `text`), with three lines of context, up to 2000 lines a file (`truncated` says when it stops short), so the Android app can show a diff itself.
8 9
- **JaCoCo coverage is read (#308):** Gradle's `jacocoTestReport` and Kover write JaCoCo XML, which a `coverage` artifact (or `POST /coverage`) may now be, beside LCOV and Cobertura: lines hit when an instruction ran, branches, methods. Its paths are relative to a source root (`io/oxygenhub/…/X.kt`), so a report's path not in the state is matched by its ending to the one file it can be.
9 10
## 0.9.4 (2026-10-25)
…
328 unchanged lines
modified crates/hub/src/flow.rs +4 −0
…
743 unchanged lines
744 744
    let heads_s = hex.join("+");
745 745
    let base = db::flow::NewRun { repo_id: row.id, bookmark, state, heads: &heads_s, pipeline_hash: "", actor, trigger, error: None };
746 746
    let id = match Pipeline::parse(&text) {
747 +
        // A scheduled tick cannot tell whether a pipeline it cannot read
748 +
        // has a schedule, so it starts nothing (#321): the push's run
749 +
        // already says what is wrong, once rather than every minute.
750 +
        Err(_) if at.is_some() => return Ok(None),
747 751
        Err(problems) => {
748 752
            let msg = problems.to_string();
749 753
            db::flow::create_run(&app.db, db::flow::NewRun { error: Some(&msg), ..base }, &[]).await.map_err(|e| e.to_string())?
…
2186 unchanged lines
modified crates/hub/tests/flow.rs +12 −0
…
2225 unchanged lines
2226 2226
    let names: Vec<String> = db::flow::jobs(&h.app.db, runs[0].id).await.unwrap().into_iter().map(|j| j.name).collect();
2227 2227
    assert_eq!(names, ["nightly"]);
2228 2228
    assert_eq!(runs[0].bookmark, "main", "on the default bookmark");
2229 +
    // #321: a pipeline that does not parse fails its push's run once, and
2230 +
    // the scheduler records nothing for it, minute after minute.
2231 +
    write(work.path(), ".flow/pipeline.kdl", "schema-version 1\n");
2232 +
    c.commit("No jobs", &[]).unwrap();
2233 +
    assert!(c.push("origin", false).unwrap().iter().all(|r| r.ok));
2234 +
    tokio::time::sleep(std::time::Duration::from_millis(300)).await;
2235 +
    let runs = runs_of(&h.app, "andy", "nightly").await;
2236 +
    assert_eq!(runs.len(), 3);
2237 +
    assert!(runs[0].error.contains("at least one job"), "{}", runs[0].error);
2238 +
    assert_eq!(oxygenhub::flow::run_due(&h.app, due).await, 0);
2239 +
    assert_eq!(oxygenhub::flow::run_due(&h.app, not_yet).await, 0);
2240 +
    assert_eq!(runs_of(&h.app, "andy", "nightly").await.len(), 3, "no scheduled runs of a broken pipeline");
2229 2241
}
2230 2242
2231 2243
#[tokio::test(flavor = "multi_thread")]
…
4318 unchanged lines