Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
28 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

A very long step log stays fast. Each chunk of a job's log is read once, into its step's log, as it arrives (`appendLog` in lib/log-lines.ts), where before every chunk joined the step's text again and read all of it from the start: a group a chunk leaves open holds the next chunk's lines, a line still being written shows until it ends, and a search reads the lines already read, once a change. A step of more than 2,000 rows draws only those on screen and 800 pixels either side (lib/log-window.ts), each row one line high until it is drawn and measured, so the space kept above and below is right however lines wrap; groups fold in the page's state rather than in a `details`, and search, following the newest line and Jump to latest work as on a short log. Each line's number links to it as GitHub's do (`#step:3:12`), opening its step and its group, scrolling to it and marking it. With a synthetic 50,000-line log in 500 chunks of 100 lines, reading it took 24.6 s in all and 105 ms for the last chunk before, and 0.5 s and 1.3 ms now; in Chromium the page drew the whole log in 2.2 s and each new chunk in 213 ms (157,000 elements), and now in 51 ms and 17 ms (385 elements). The Actions guide says so.1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { ROW_HEIGHT, rowAt, rowStarts, windowOf } from "./log-window.ts";
5
6test("rows start where the rows above them end, measured or not", () => {
7 const starts = rowStarts(4, (index) => (index === 1 ? 60 : undefined));
8 assert.deepEqual([...starts], [0, ROW_HEIGHT, ROW_HEIGHT + 60, 2 * ROW_HEIGHT + 60, 3 * ROW_HEIGHT + 60]);
9 assert.equal(rowAt(starts, 0), 0);
10 assert.equal(rowAt(starts, ROW_HEIGHT), 1);
11 assert.equal(rowAt(starts, ROW_HEIGHT + 59), 1);
12 assert.equal(rowAt(starts, ROW_HEIGHT + 60), 2);
13 assert.equal(rowAt(starts, 10_000), 3, "past the end is the last row");
14});
15
16test("only the rows on screen and a little around them are drawn", () => {
17 const starts = rowStarts(50_000, () => undefined);
18 // The screen shows rows 1000 to 1040.
19 const [from, to] = windowOf(starts, 1000 * ROW_HEIGHT, 1040 * ROW_HEIGHT, 200);
20 assert.deepEqual([from, to], [990, 1051]);
21 // At the very end, following the newest line.
22 const end = starts[50_000]!;
23 assert.deepEqual(windowOf(starts, end - 800, end, 200), [49_950, 50_000]);
24 // The log above or below the screen draws a few rows at the near end.
25 assert.deepEqual(windowOf(starts, -5000, -4000, 200), [0, 20]);
26 assert.deepEqual(windowOf(starts, end + 4000, end + 5000, 200), [49_980, 50_000]);
27 assert.deepEqual(windowOf(rowStarts(0, () => undefined), 0, 100), [0, 0]);
28});