# sb-builder: named builds and per-package results Date: 2026-10-21 Status: draft ## Goal Two fixes to how slackrepo jobs run several packages: 1. A never-built package can be built from the GUI by name. 2. A job that builds several packages says which ones failed, and its status reflects that. One job keeps running every package given to it. Splitting into one job per package was considered and rejected: slackrepo already orders deps across the whole set, builds a shared dep once and goes on past a failed item. Splitting would add one preview, one gpg unlock and one publish per package, for nothing but the ability to cancel a single package. ## 1. Named packages run `build`, not `update` slackrepo looks up the items named to `update` in its package database only (`find_items -p`, `parsefunctions.sh`), so a package never built before ends `bad: No matches found for update command`. Deps of named items use `-ps` (database, then the SlackBuild tree) and are found. `build` on named items does what `update` would: `build_command` sets an outdated item to `update` and rebuilds it, a new one to `add` and builds it, an up-to-date one to `ok` and skips it. The one thing only `update` does is remove the packages of an item whose SlackBuild is gone (e.g. moved to the official tree). That cannot happen for a named item: `kind_slackrepo` accepts only names with a SlackBuild dir, and the Packages tab lists only those. Changes (GUI only, the helper is unchanged): - `HintResultDialog.build_requested` (`mainwindow.py`) starts `slackrepo build --preview ` instead of `update`. - The Packages tab drops its per-row **Update** action: **Build** now does the same thing. - **Update all** stays `slackrepo update` with no items: it scans the whole package database and is what removes packages whose SlackBuild is gone. ## 2. Per-package results of a job slackrepo exits 0 after a full run whatever its items did. It exits non-zero only on setup errors. Today a run where some packages failed shows as `ok`. slackrepo records each item's outcome in its database: `buildresults(itemid, time, result)`, `time` in epoch seconds, one row per item (insert or replace), written by `log_itemfinish` for build, rebuild and update. Results: `ok`, `skipped`, `unsupported`, `failed`, `aborted` (skipped because a dep failed), `bad`, `removed`. ### Helper (`sbb-remote`) In `cmd_run`, after a real slackrepo job ends (`signs(kind, args)`, i.e. not `--preview`), read the rows with `time >= meta["start"]` from `slackrepo_db` (read-only, as `cmd_results`) into `meta["results"] = {itemid: result}`. If any result is `failed`, `aborted` or `bad` and the exit was 0, the job's status is `failed`. A database error leaves `results` unset and the status as the exit code says: the build already happened, a missing summary must not lose it. No new job status: `failed` is already handled everywhere (Jobs tab, notifications, badge). `job-list` carries `results` with the rest of the meta. The flock serializes jobs, so rows newer than the job's start are this job's. `rebuild-tree` does not touch `buildresults` and is unaffected. `publish` is a separate job and keeps its own exit status. ### GUI - Jobs tab: a slackrepo job with `results` shows a one-line count in its details, e.g. `3 ok, 1 failed, 1 aborted`. - Notification body (`fmt.outcome`): the same count, plus the names of the failed items, so a failed build says what failed without opening the app. - Next step (UI guideline 5): when a real slackrepo job started this session ends with any non-`ok` result, a non-modal `BuildResultDialog` lists every item with its result chip. Per row: **Log** opens the existing `results.LogViewer` (`build-log `). Bottom: **Retry failed** starts `slackrepo build --preview` on the `failed` and `aborted` items (not `bad`: those need a fix first), **Close**. It can be reopened from the Jobs tab ribbon for the highlighted job, like a preview's next step. ## Tests - `test_remote.py`: `cmd_run` on a fake slackrepo that writes rows to a temp `buildresults` db and exits 0: `results` filled; status `failed` when one row is `failed`, `ok` when all are `ok`; rows older than the job's start ignored; a preview job gets no `results`. - `test_gui.py`: Packages tab has no Update action; the hint result's build request starts `build`; a finished job with a failed result opens `BuildResultDialog`, and Retry failed starts `build --preview` on the failed and aborted items only.