From 104f590b221f7ae4acdeb7308b085bc55ac8c1fd Mon Sep 17 00:00:00 2001 From: Robbe Verhelst Date: Sat, 26 Sep 2026 12:19:36 +0200 Subject: [PATCH] docs: getting started leads with the app, and running the action yourself is its own page Get started now installs the GitHub App: the onboarding pull request adds the workflow and a starter sluiceway.yaml, and the console guides the rest. The steps without the app move, whole, to get-started/run-the-action-yourself, and a new page says how the app and the action work together: the webhook tick, the action's resolve as the fallback, where deploys run and who holds credentials. Old get-started fragments go on to the new page. The app pages link console.sluiceway.dev, where app.sluiceway.dev now redirects. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/content/docs/get-started.mdx | 102 ++++++++++++++++++ .../get-started/the-app-and-the-action.mdx | 75 +++++++++++++ src/content/docs/hosted-app/install.mdx | 4 +- src/content/docs/hosted-app/using-the-app.mdx | 4 +- src/content/docs/index.mdx | 3 +- src/lib/anchor-redirects.ts | 4 + src/lib/pages.ts | 33 ++++-- src/lib/routes.ts | 7 +- test/links.test.ts | 8 +- 9 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 src/content/docs/get-started.mdx create mode 100644 src/content/docs/get-started/the-app-and-the-action.mdx diff --git a/src/content/docs/get-started.mdx b/src/content/docs/get-started.mdx new file mode 100644 index 0000000..e68806f --- /dev/null +++ b/src/content/docs/get-started.mdx @@ -0,0 +1,102 @@ +--- +title: Get started +description: Install the Sluiceway GitHub App, merge the pull request it opens with the workflow and a first sluiceway.yaml, and let the console guide the rest. +headerPicture: + picture: first-run + alt: The scan found no stacks yet, Penny stands beside an empty channel +--- + +import Callout from "../../components/Callout.astro"; +import Steps from "../../components/Steps.astro"; +import { page, ROUTES } from "../../lib/routes"; + +

+ Install the Sluiceway GitHub App. It opens one pull request per repo that adds the workflow + and a first sluiceway.yaml, and the console guides you through the rest. +

+ +The app is the action, set up for you, with a console. Every deploy still runs in your own +GitHub Actions, with your own cloud credentials. The app holds no cloud credential and runs no +infrastructure as code. It is free for 5 repos. + + + +## Install the app + +Open the Sluiceway app on GitHub, choose +**Install**, pick the org or account, and choose all repos or only some. You can change the repos +later in GitHub's settings for the installation. + +Then sign in at console.sluiceway.dev with GitHub. +The console lists every repo of the installation. A repo with no dashboard yet is under Not set up +yet, with its onboarding pull request. + +Only repos with a dashboard count toward your plan, so installing on a whole org costs nothing. +The Free plan covers 5 of them. See Plans and adopted repos. + +## Merge the onboarding pull request + +The pull request is written by the action's own init and check, so it holds what adding the +action by hand would give you: + +- **The workflow** at `.github/workflows/deploy-dashboard.yml`, which runs `sluiceway/sluiceway@v0`. +- **A starter `sluiceway.yaml`**, or one line added to the one the repo has: `sluiceway[bot]` in + `recordWriters`, so ticks can go through the app. +- **Its description**: the stacks the check found, the dashboard the repo would get, and per + stack the credentials it needs, as names, with a link to the repo's Actions secrets settings. + +Before you merge, add the secrets it names, or load them another way from +Credentials and your own tooling. When your +infrastructure cannot be reached from GitHub's runners, point the workflow at a +self-hosted runner. + +Then merge. The push of that merge starts the first scan: it previews every stack and writes the +dashboard issue with one row per stack. Nothing deploys until someone ticks a box. The console +moves the repo from Not set up yet to its stacks, and when the first scan fails it says why in one +sentence, with a link to the page that fixes it. + +Install the app has the permissions GitHub asks you to +accept, everything the pull request holds, and what to do when there is none. + + + A tick asks for a deploy of that stack, production included. Without a tick rule, anyone with + write access to the repo can tick. Narrow it with tickers in + sluiceway.yaml, or gate the deploy job with a GitHub Environment. See{" "} + Who can tick. + + +## Tick + +Tick a stack's box on the dashboard issue, or in the console on the repo's Dashboard tab. The app +picks the tick up within about a second, judges it with the action's own tick rule, opens the +deployment record and starts your workflow. Your runner previews the stack again and deploys only +when the change is the one you ticked. + +Using the dashboard explains the rows and the boxes, and +Using the app the console. + +## Without the app + +The action runs on its own too: the same deploys, with the dashboard issue as the only dashboard. +Run the action yourself takes you through it step by +step. How the app and the action work together says what the +app adds, and what happens to a tick when the app is down. diff --git a/src/content/docs/get-started/the-app-and-the-action.mdx b/src/content/docs/get-started/the-app-and-the-action.mdx new file mode 100644 index 0000000..73fd648 --- /dev/null +++ b/src/content/docs/get-started/the-app-and-the-action.mdx @@ -0,0 +1,75 @@ +--- +title: How the app and the action work together +description: The app picks a tick up by webhook and starts your workflow, which deploys in your runners with your credentials, and ticks still deploy when the app is down. +sidebar: + label: The app and the action +headerPicture: + picture: deploying-0 + alt: A stack is deploying, the gate is open, one crate goes through it and water runs downstream +--- + +import { glossary, page, ROUTES } from "../../../lib/routes"; + +

+ The action does the work: it scans, previews and deploys, in your GitHub Actions, with your + credentials. The app sets it up, makes a tick start sooner, and adds the console. It never + replaces the action. +

+ +## Where deploys run + +Every deploy runs in your own GitHub Actions, on your runners, with your own cloud credentials, +with or without the app. The app holds no cloud credential, never asks for one, and runs no +infrastructure as code: it never previews or deploys a stack. See +What the app keeps and never keeps. + +## A tick with the app + +When you tick a box on the dashboard issue: + +1. **GitHub sends the app a webhook**, and the app picks the tick up within about a second. +2. **The app judges the tick** with the action's own code: the same + tick rule your workflow uses, and your permission on the + repo, read live from GitHub. +3. **The app opens the deployment record** with you + as the ticker, and starts your workflow. +4. **Your workflow deploys the record.** It previews the stack again and deploys only when the + fresh preview gives the diff hash you approved. A change that moved in between is refused. + +A tick in the console, or from the command line, takes the same path from step 2. + +## The fallback: the action's own resolve + +The action judges ticks itself, as it always has. The edit of the issue starts your workflow, and +its `resolve` step checks who ticked, opens the record and deploys it, about 20 seconds after the +tick. With the app installed, that step stays in place as the fallback. + +- **When the app has opened the record first**, `resolve` finds it open and does nothing more, so + the stack deploys once. +- **When the app is down**, ticks on the issue still deploy, at the old speed. A down app costs a + tick nothing but the time it saves. + +Nothing needs to change in your workflow for either path. See +The workflow for what each event runs. + +## What recordWriters allows + +Ticks from the console and the command line go through the app alone, so the workflow has to +accept the records the app opens. That takes one line in `sluiceway.yaml`, which the onboarding +pull request adds: + +```yaml title="sluiceway.yaml" +recordWriters: + - sluiceway[bot] +``` + +Without it, the app judges no tick on that repo: ticks on the issue deploy through the action's +own `resolve`, and a box in the console opens the dashboard on GitHub. See +The recordWriters line. + +## The action alone + +Without the app, you get the same deploys, with the dashboard issue as the only dashboard: no +console, no org view, and ticks that start at the action's own speed. It is the path for a team +that grants no third-party app. Run the action yourself +sets it up step by step. diff --git a/src/content/docs/hosted-app/install.mdx b/src/content/docs/hosted-app/install.mdx index 73e4401..583f8f8 100644 --- a/src/content/docs/hosted-app/install.mdx +++ b/src/content/docs/hosted-app/install.mdx @@ -17,6 +17,8 @@ import { page } from "../../../lib/routes"; The app does not replace the action. Your workflow keeps running in your runners, with your credentials, and the dashboard issue in each repo keeps working as it does without the app. +How the app and the action work together +follows a tick through both. the Sluiceway app on GitHub **Install**, pick the org or account, and choose all repos or only some. You can change the repos later in GitHub's settings for the installation, and the app's Settings tab links there. -Then sign in at app.sluiceway.dev with GitHub. You see +Then sign in at console.sluiceway.dev with GitHub. You see the installations of the orgs and accounts you belong to, and nothing else. Installing the app on repos that have no dashboard costs nothing: only repos with a dashboard diff --git a/src/content/docs/hosted-app/using-the-app.mdx b/src/content/docs/hosted-app/using-the-app.mdx index c1387ef..45ece36 100644 --- a/src/content/docs/hosted-app/using-the-app.mdx +++ b/src/content/docs/hosted-app/using-the-app.mdx @@ -13,7 +13,7 @@ import { glossary, page, ROUTES } from "../../../lib/routes"; words. Every row it draws leads back to its repo and its dashboard on GitHub.

-Sign in at app.sluiceway.dev with GitHub. The app reads +Sign in at console.sluiceway.dev with GitHub. The app reads which installations you may see once, when you sign in, and keeps no token of yours. A session lasts eight hours, so a change of your membership on GitHub shows at your next sign-in. @@ -22,7 +22,7 @@ has the tabs Overview, Insights, Audit and Settings. A repo has Dashboard, Insig ## The org view -The org's Overview tab is every stack of every repo the app covers, at `app.sluiceway.dev/`. +The org's Overview tab is every stack of every repo the app covers, at `console.sluiceway.dev/`. - **The counts** of the five states, pending, deploying, drifted, preview failed and in sync, and when the last scan ran. Queued stacks count as deploying, and their rows still say queued. diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx index 172a252..d36de18 100644 --- a/src/content/docs/index.mdx +++ b/src/content/docs/index.mdx @@ -46,7 +46,7 @@ import "../../styles/landing.css";
- Add Sluiceway one step at a time, starting with a check that changes nothing. + Install the GitHub App. It opens one pull request with the workflow and a first sluiceway.yaml, and the console guides the rest. Load your cloud and state credentials on Sluiceway's step or in a step right before it, or name an env file that Sluiceway reads and masks. @@ -57,6 +57,7 @@ import "../../styles/landing.css";
+

Without the app, run the action yourself: the same deploys, with the issue as the only dashboard. How the app and the action work together says what each one does.

The guides, in order:

  • The workflow
  • diff --git a/src/lib/anchor-redirects.ts b/src/lib/anchor-redirects.ts index add5422..2e977cf 100644 --- a/src/lib/anchor-redirects.ts +++ b/src/lib/anchor-redirects.ts @@ -20,6 +20,10 @@ export const ANCHOR_REDIRECTS: Record> = { "4-load-your-credentials": "guides/credentials", "start-read-only": "guides/read-only-trial", "pin-a-commit": "guides/workflow#pin-a-commit", + // Getting started leads with the app since 2026-09-26, and the steps without it moved to a + // page of their own. + requirements: "get-started/run-the-action-yourself#requirements", + "get-started": "get-started/run-the-action-yourself#get-started", }, // v0.12.0 moved the README's "What it does not do yet" into the Limits of the dashboard's use. "not-in-v1": { diff --git a/src/lib/pages.ts b/src/lib/pages.ts index b03d3bd..0ef5a50 100644 --- a/src/lib/pages.ts +++ b/src/lib/pages.ts @@ -78,6 +78,16 @@ export const SLICE_3 = { theHeader: "the-header", }; +/** + * The pages that open Getting started, written in src/content/docs. The page that adds the + * action by hand is read from the action, under `runTheActionYourself`. + */ +export const GET_STARTED = { + withTheApp: "get-started", + runTheActionYourself: "get-started/run-the-action-yourself", + together: "get-started/the-app-and-the-action", +} as const; + /** * The pages about the hosted app, in sidebar order. They are written in src/content/docs: the * action has no Markdown about the app. @@ -468,16 +478,24 @@ export function pages(repoUrl: string, base: string): Page[] { ], }, { - id: "get-started", - title: "Get started", + id: GET_STARTED.runTheActionYourself, + title: "Run the action yourself", description: - "Add Sluiceway to a repo of infrastructure as code: check what you need, run the check, then add the workflow, the tick rule and your credentials.", + "Add Sluiceway to a repo without the app: check what you need, run the check, then add the workflow, the tick rule and your credentials.", source: README, headerPicture: { picture: "first-run", alt: "The scan found no stacks yet: Penny stands beside an empty channel", }, parts: [ + generated( + README, + [ + "The action runs on its own, with no app installed and nothing hosted: the same scans, the same ticks and the same deploys, in your runners with your credentials, and the dashboard issue is the only dashboard. It is the path for a team that grants no third-party app, or that wants to set every step up by hand.", + "", + `With the app, [one pull request](${base}/${GET_STARTED.withTheApp}/) holds the workflow and a first \`sluiceway.yaml\`, and the console guides the rest. [How the app and the action work together](${base}/${GET_STARTED.together}/) says what the app adds and what stays the same.`, + ].join("\n"), + ), // First, so a reader checks the runner and tool versions before any step. Here since the // README moved it, so get-started/#requirements keeps working. sectionPart("docs/reference.md", "Requirements"), @@ -807,8 +825,9 @@ export function covered(): Covered[] { const slugs = githubSlugs(README); return [ { link: README, page: SLICE_3.overview }, - // Get started opens on Requirements, so a link to the README section lands on the page top. - { link: `${README}#get-started`, page: "get-started" }, + // Run the action yourself opens on Requirements, so a link to the README section lands on + // the page top. + { link: `${README}#get-started`, page: GET_STARTED.runTheActionYourself }, // The index of the action's docs: the sidebar is this site's. { link: "docs/README.md", page: SLICE_3.overview }, { link: "docs/adr", page: "why" }, @@ -994,7 +1013,9 @@ export function sidebar(): SidebarItem[] { label: "Start", items: [ { label: "Overview", link: "/" }, - { slug: "get-started" }, + { slug: GET_STARTED.withTheApp }, + { slug: GET_STARTED.runTheActionYourself }, + { slug: GET_STARTED.together }, ...(written(SLICE_3.whatItLooksLike) ? [{ slug: SLICE_3.whatItLooksLike }] : []), { slug: "how-it-works" }, { slug: "using-the-dashboard" }, diff --git a/src/lib/routes.ts b/src/lib/routes.ts index 484f8b2..f39ec15 100644 --- a/src/lib/routes.ts +++ b/src/lib/routes.ts @@ -2,7 +2,7 @@ // id from src/lib/pages.ts and goes through its `urlFor`, so the base is added the same way // everywhere. A page id that pages.ts does not define stops the build. -import { githubSlug, HOSTED_APP, pages, SLICE_3, urlFor } from "./pages"; +import { GET_STARTED, githubSlug, HOSTED_APP, pages, SLICE_3, urlFor } from "./pages"; import { REPO_URL } from "./source"; const BASE = import.meta.env.BASE_URL.replace(/\/$/, ""); @@ -17,6 +17,7 @@ export function page(id: string): string { SLICE_3.overview, SLICE_3.whatItLooksLike, SLICE_3.theHeader, + ...Object.values(GET_STARTED), ...Object.values(HOSTED_APP), ]); const path = id.split("#")[0] ?? ""; @@ -27,7 +28,9 @@ export function page(id: string): string { } export const ROUTES = { - getStarted: page("get-started"), + getStarted: page(GET_STARTED.withTheApp), + runTheActionYourself: page(GET_STARTED.runTheActionYourself), + appAndAction: page(GET_STARTED.together), configuration: page("guides/configuration"), credentials: page("guides/credentials"), usingTheDashboard: page("using-the-dashboard"), diff --git a/test/links.test.ts b/test/links.test.ts index 161388b..255e9d9 100644 --- a/test/links.test.ts +++ b/test/links.test.ts @@ -12,14 +12,18 @@ const blob = `${REPO_URL}/blob/${TAG}`; describe("resolveLink", () => { const cases: [from: string, href: string, want: string][] = [ // A section of another file that a page shows, from docs/. - ["docs/workflow.md", "reference.md#requirements", "/docs/get-started/#requirements"], + [ + "docs/workflow.md", + "reference.md#requirements", + "/docs/get-started/run-the-action-yourself/#requirements", + ], [ "docs/security.md", "workflow.md#with-github-environments", "/docs/guides/workflow/#with-github-environments", ], // A README section shown without its heading lands on the page itself. - ["docs/workflow.md", "../README.md#get-started", "/docs/get-started/"], + ["docs/workflow.md", "../README.md#get-started", "/docs/get-started/run-the-action-yourself/"], // A file's h1 is the page title: a link to it lands on the page, as on GitHub. ["docs/read-only-trial.md", "workflow.md#the-workflow", "/docs/guides/workflow/"], // Whole files, and headings in them.