Progress in logs
Keep a progress bar readable in a CI log by updating it in steps — one line per tenth of the work instead of one per item.
Off a terminal every state that changes the text is a line. 12/200 items · 6% changes on
every item, so a loop that updates on every item writes two hundred lines. The bar on a
terminal does not need every item either: update when the work has moved by a step.
import { hoist } from 'flagstaff/loop';
import { progress } from 'flagstaff/progress';
import { json, rt } from './rt.mjs';
const items = Array.from({ length: 200 }, (_, i) => i);
const total = items.length;
const step = total / 10;
const flag = hoist(progress(), rt, { done: 0, total, label: 'items' }, { json });
let reported = 0;
for (const [i] of items.entries()) {
// ... the work for one item ...
const done = i + 1;
if (done === total || done - reported >= step) {
flag.update({ done, total, label: 'items' });
reported = done;
}
}
flag.lower();0/200 items · 0%
20/200 items · 10%
40/200 items · 20%
60/200 items · 30%
80/200 items · 40%
100/200 items · 50%
120/200 items · 60%
140/200 items · 70%
160/200 items · 80%
180/200 items · 90%
200/200 items · 100%The final update is always sent, so the last line is the whole count. lower() without a
state keeps the last one and, off a terminal, writes nothing more.
Build steps as a task list
Run a list of async steps under a task list that animates on a terminal, prints each step once as it settles in CI, and stops at the first failure.
Results an agent can read
Print a results table that is a grid on a terminal, header-and-value lines in a log, and plain JSON rows under --json.