Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "vendor/sluiceway"]
path = vendor/sluiceway
url = https://github.com/sluiceway/sluiceway.git
branch = v0.47.0
branch = v0.48.0
18 changes: 14 additions & 4 deletions src/components/CountsLine.astro
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
---
// CountsLine: the dashboard's counts, in the dashboard's own order. A zero keeps its pill.
// CountsLine: the dashboard's counts, in the dashboard's own order. A zero keeps its pill,
// except busy, which the dashboard shows only when a stack is busy, with the white dot of a
// zero (record 0117).
interface Props {
counts: { pending?: number; deploying?: number; failed?: number; "in-sync"?: number };
counts: {
pending?: number;
deploying?: number;
failed?: number;
"in-sync"?: number;
busy?: number;
};
}

const ORDER = ["pending", "deploying", "failed", "in-sync"] as const;
const ORDER = ["pending", "deploying", "failed", "in-sync", "busy"] as const;
const WORD = {
pending: "pending",
deploying: "deploying",
failed: "preview failed",
"in-sync": "in sync",
busy: "busy",
} as const;

const { counts } = Astro.props;
const shown = ORDER.filter((k) => k !== "busy" || (counts.busy ?? 0) > 0);
---

<div class="sw-counts not-content">
{
ORDER.map((k) => {
shown.map((k) => {
const n = counts[k] ?? 0;
return (
<span class:list={["sw-count", `sw-count--${k}`, { "sw-count--zero": n === 0 }]}>
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/style-check.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ picture it belongs to.

## Counts line

<CountsLine counts={{ pending: 4, deploying: 0, failed: 1, "in-sync": 8 }} />
<CountsLine counts={{ pending: 4, deploying: 0, failed: 1, "in-sync": 8, busy: 1 }} />

A stack id is written whole, as in `apps/web:prod`, and never wraps.

Expand Down
20 changes: 16 additions & 4 deletions src/content/docs/the-header.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ export const pictures = [
},
{
picture: "failing-0",
alt: "Something failed: the gate is stuck half open over a log, with a red lamp",
alt: "A preview or a deploy failed: the gate is stuck half open over a log, with a red lamp",
},
{
picture: "failing-4",
alt: "Something failed, 4 stacks are pending: four crates wait behind the gate, which is stuck half open over a log",
alt: "A preview or a deploy failed, 4 stacks are pending: four crates wait behind the gate, which is stuck half open over a log",
},
];

Expand All @@ -58,7 +58,9 @@ export const states = headerStates(pictures.map(({ picture }) => picture));
one of {states.count} states.
</p>

When more than one state applies, the first wins, in this order: {states.order}.
When more than one state applies, the first wins, in this order: {states.order}. A
<a href={glossary("Busy stack")}>busy stack</a>, one whose lock another update held when the
scan ran, makes no header failing: nothing is wrong with it, and the next scan previews it.

Upstream is on the left, where crates pile up while changes are pending. Downstream is on the
right, where the water runs while a stack deploys. The pending, queued, deploying and failing
Expand Down Expand Up @@ -95,11 +97,21 @@ The signs do not move, and nothing else in the picture changes.
},
{
picture: "failing-4-deletes-replaces",
alt: "Something failed, 4 stacks are pending, some changes delete or replace resources: the gate is stuck over a log and both signs stand in the water",
alt: "A preview or a deploy failed, 4 stacks are pending, some changes delete or replace resources: the gate is stuck over a log and both signs stand in the water",
},
]}
/>

## The alt text says it in words

Where the picture does not load, and in a screen reader, the header is its alt text. It names
the state and the pending count, `Sluiceway: 4 stacks are pending`, and a sign adds its fact,
`, some changes delete or replace resources`. A failing header names what failed and how many,
in the numbers of the counts line under it: `Sluiceway: 1 preview failed`,
`Sluiceway: 2 previews and 1 deploy failed`. The picture is the same jam for any number, so its
own label stays `Sluiceway: something failed`. No picture shows a busy stack, so the alt text
names it last: `, 1 stack is busy`.

## The water rises in five steps

Behind the closed or jammed gate the water rises in five steps, with one amber mark each on the
Expand Down
12 changes: 10 additions & 2 deletions src/content/docs/what-it-looks-like.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ export const intro = readmeDashboardIntro();
downstream because two stacks deploy, and both signs: a pending row deletes resources and
another replaces one. <a href={ROUTES.theHeader}>The header</a> shows every picture.
- **The <a href={glossary("Counts line")}>counts line</a>.** How many stacks are pending, drifted, deploying, preview failed and in
sync, each behind its <a href={glossary("Count dot")}>count dot</a>, and how many pending stacks
delete or replace resources. Under it, the
sync, each behind its <a href={glossary("Count dot")}>count dot</a>, how many pending stacks
delete or replace resources, and, only when there is one, how many stacks are
<a href={glossary("Busy stack")}>busy</a>. Under it, the
<a href={glossary("Scan line")}>scan line</a> says which commit the last scan checked out, when, in which run, and when the
last full scan was. While a scan runs, a <a href={glossary("Scan-running line")}>scan-running line</a> under it says
since when and links the run, which this example does not show.
Expand Down Expand Up @@ -66,6 +67,13 @@ export const intro = readmeDashboardIntro();
box deploys them, as a tick on each row. Each stack is judged by its own
<a href={glossary("Tick rule")}>tick rule</a> and gets its own fresh preview. If a row changes before anyone ticks the
confirm box, the confirm box goes and the bulk box comes back.
- **Preview failed and Busy.** A stack whose preview failed twice in one scan, after its
<a href={glossary("Second try")}>second try</a>, sits under Preview failed. Its row has no
box, says why, and links the run whose job log holds the tool's own words. A
<a href={glossary("Busy stack")}>busy stack</a>, one whose lock another update held on both
tries, sits under Busy. Its row starts with `busy:`, names the reason,
`another update holds the stack's lock`, and says that the next scan previews it. Nothing is
wrong with it, and the header does not turn failing. This example shows neither section.
- **<a href={glossary("In sync")}>In sync</a>.** The stacks with nothing to deploy, folded under their count, and under them the
<a href={glossary("Ignored stack")}>stacks left out by ignore</a>, each with its reason.
- **Recently deployed, the <a href={glossary("Trail")}>trail</a>.** Every deploy that ended, newest first, one line each: its
Expand Down
11 changes: 9 additions & 2 deletions src/lib/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ export const RECORD_PICTURES: Record<string, HeaderPicture> = {
// The header states, and bad news wins: the state that wins over all the others.
"0031": {
picture: "failing-0",
alt: "Something failed: the gate is stuck half open over a log, with a red lamp",
alt: "A preview or a deploy failed: the gate is stuck half open over a log, with a red lamp",
},
// The files named by role: the first of them, the scan that found nothing yet.
"0033": {
Expand Down Expand Up @@ -418,7 +418,7 @@ export const RECORD_PICTURES: Record<string, HeaderPicture> = {
// nine pending stacks and one failed preview showed two crates behind the jam.
"0066": {
picture: "failing-9",
alt: "Something failed, 9 stacks are pending: nine crates wait behind the gate, which is stuck half open over a log",
alt: "1 preview failed, 9 stacks are pending: nine crates wait behind the gate, which is stuck half open over a log",
},
// A delete sign next to the replace sign, up to 20 crates, and the queued state: all three.
"0075": {
Expand All @@ -431,6 +431,13 @@ export const RECORD_PICTURES: Record<string, HeaderPicture> = {
picture: "queued-0",
alt: "Queued behind dependencies: a ticked crate is tied up at the closed gate",
},
// The failing header's alt text names what failed and how many. The dashboard the record
// came from had one failed preview, nothing pending and every other stack in sync: the jam
// with no crate behind it.
"0118": {
picture: "failing-0",
alt: "1 preview failed: the gate is stuck half open over a log, with a red lamp",
},
};

export function recordId(record: Pick<DecisionRecord, "file">): string {
Expand Down
15 changes: 14 additions & 1 deletion test/walk-through.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,21 @@ describe("the walk-through", () => {
expect(walk).toContain('reference/glossary/#failure-line"');
});

test("says what a busy stack's row reads, as the dashboard writes it", () => {
expect(walk).toMatch(/<code[^>]*>busy:<\/code>/);
expect(walk).toMatch(/<code[^>]*>another update holds the stack(?:'|&#39;|’)s lock<\/code>/);
expect(walk).toContain('reference/glossary/#busy-stack"');
});

test("names the lines the example does not draw, linked to the glossary", () => {
for (const term of ["scan-running-line", "cost-line", "policy", "preview-failure"]) {
for (const term of [
"scan-running-line",
"cost-line",
"policy",
"preview-failure",
"second-try",
"busy-stack",
]) {
expect(walk).toContain(`reference/glossary/#${term}"`);
}
});
Expand Down
2 changes: 1 addition & 1 deletion vendor/sluiceway
Submodule sluiceway updated 82 files
+1 −1 .release-please-manifest.json
+7 −0 CHANGELOG.md
+12 −4 CONTEXT.md
+2 −0 CONTRIBUTING.md
+5 −5 README.md
+3 −2 action.yml
+5 −5 assets/example-dashboard.md
+2 −0 dist/cli.js
+186 −32 dist/index.js
+2 −0 docs/adr/0009-marker-format.md
+2 −0 docs/adr/0012-one-scan-job-with-a-bounded-pool-of-previews.md
+2 −0 docs/adr/0022-the-tools-own-words-stay-in-the-job-log.md
+2 −0 docs/adr/0029-the-body-layout-puts-pending-first-and-hides-only-what-is-calm.md
+2 −0 docs/adr/0031-the-header-has-six-states-and-bad-news-wins.md
+2 −0 docs/adr/0037-the-summary-has-a-budget-too-and-the-job-log-holds-the-rest.md
+2 −0 docs/adr/0040-the-header-and-the-two-lines-under-it-are-centered-and-every-count-has-a-dot.md
+2 −0 docs/adr/0066-the-failing-and-deploying-pictures-show-one-crate-per-pending-stack-too.md
+2 −0 docs/adr/0114-the-dashboard-layout-is-a-set-of-keys-that-move-and-hide-and-never-drop-a-row-block.md
+48 −0 docs/adr/0117-a-preview-that-fails-is-tried-once-more-and-a-stack-whose-lock-is-held-is-busy.md
+35 −0 docs/adr/0118-the-failing-header-names-what-failed-and-the-preview-failed-section-says-what-comes-next.md
+3 −1 docs/build-plan.md
+3 −0 docs/later.md
+1 −0 docs/onboarding-log.md
+1 −1 docs/reference.md
+3 −0 docs/roadmap.md
+4 −0 docs/using-the-dashboard.md
+1 −0 docs/what-sluiceway-writes.md
+1 −1 package.json
+29 −0 scripts/fixtures/opentofu-scenarios.ts
+123 −64 scripts/fixtures/recorder.ts
+10 −0 scripts/fixtures/scenarios.ts
+24 −0 scripts/record-fixtures.ts
+9 −2 src/adapters/opentofu/preview.ts
+38 −0 src/adapters/opentofu/state-lock.ts
+7 −0 src/core/failure-reason.ts
+47 −0 src/core/preview-retry.ts
+3 −0 src/modes/scan-job.ts
+108 −11 src/modes/scan.ts
+53 −10 src/render/body.ts
+11 −1 src/render/dashboard-facts.ts
+3 −0 src/render/dots.ts
+13 −0 src/render/marker.ts
+4 −0 src/render/preview-result.ts
+12 −3 src/render/row.ts
+12 −1 src/render/summary.ts
+14 −2 src/render/voice.ts
+8 −0 test/adapters/opentofu/family-replay.test.ts
+50 −0 test/adapters/opentofu/preview.test.ts
+16 −0 test/adapters/pulumi/preview.test.ts
+64 −0 test/core/preview-retry.test.ts
+1 −0 test/docs/written-surface.test.ts
+0 −0 test/fixtures/opentofu/v1.11.0/state-locked/plan.stderr
+2 −0 test/fixtures/opentofu/v1.11.0/state-locked/plan.stdout
+28 −0 test/fixtures/opentofu/v1.11.0/state-locked/recording.json
+0 −0 test/fixtures/opentofu/v1.12.6/state-locked/plan.stderr
+2 −0 test/fixtures/opentofu/v1.12.6/state-locked/plan.stdout
+28 −0 test/fixtures/opentofu/v1.12.6/state-locked/recording.json
+0 −0 test/fixtures/pulumi/v3.229.0/preview-locked/preview.stderr
+395 −0 test/fixtures/pulumi/v3.229.0/preview-locked/preview.stdout
+25 −0 test/fixtures/pulumi/v3.229.0/preview-locked/recording.json
+0 −0 test/fixtures/pulumi/v3.263.0/preview-locked/preview.stderr
+398 −0 test/fixtures/pulumi/v3.263.0/preview-locked/preview.stdout
+25 −0 test/fixtures/pulumi/v3.263.0/preview-locked/recording.json
+0 −0 test/fixtures/terraform/v1.14.0/state-locked/plan.stderr
+2 −0 test/fixtures/terraform/v1.14.0/state-locked/plan.stdout
+28 −0 test/fixtures/terraform/v1.14.0/state-locked/recording.json
+0 −0 test/fixtures/terraform/v1.16.3/state-locked/plan.stderr
+2 −0 test/fixtures/terraform/v1.16.3/state-locked/plan.stdout
+28 −0 test/fixtures/terraform/v1.16.3/state-locked/recording.json
+2 −2 test/modes/__snapshots__/scan-example.test.ts.snap
+2 −2 test/modes/__snapshots__/scan-stale-failure.test.ts.snap
+2 −0 test/modes/harness.ts
+12 −7 test/modes/scan-example.test.ts
+260 −0 test/modes/scan-second-try.test.ts
+2 −1 test/modes/scan.test.ts
+97 −97 test/render/__snapshots__/body.test.ts.snap
+2 −2 test/render/__snapshots__/budget-fixtures.test.ts.snap
+47 −17 test/render/body.test.ts
+102 −0 test/render/busy-row.test.ts
+1 −0 test/render/dashboard-facts.test.ts
+11 −4 test/render/voice.test.ts
+75 −0 test/scripts/recorder.test.ts
Loading