Commit Graph
7 Commits
Author SHA1 Message Date
Nick Vigilante 8853f5535a fix(.github/workflows): raise docs indexer POST timeout to 300s (#27095)
## Problem

The `algolia-and-isr` job's "POST to coder.com docs indexer" step aborts
at `curl --max-time 120`. A whole-branch docs reindex fetches and
extracts a few hundred pages server-side and runs longer than two
minutes, so curl gives up before the handler responds:

```
curl: (28) Operation timed out after 120000 milliseconds
```

The step never receives the handler's result even though the server is
still processing, so a legitimate reindex is reported as a failure.

## Fix

Raise `--max-time` on that POST from `120` to `300`, matching the
indexer's server-side function budget so curl waits for the response
instead of aborting mid-reindex.

- Only the Algolia indexer POST is changed.
- The `vercel-rebuild` deploy-hook curl is left at `120` (it returns
immediately).
- No behavior change beyond the timeout. Validated with `actionlint`.

<details>
<summary>Rationale &amp; decision log</summary>

- The indexer handler performs an **atomic whole-branch reindex**: fetch
the manifest, fetch + extract every navigable page, then replace the
index slice. On a large ref that is a few hundred pages at concurrency
8, which comfortably exceeds the old 120s curl budget.
- `300s` aligns curl with the handler's own server-side function
ceiling, so the workflow observes the real response (or a real error)
instead of a false client-side timeout.
- The deploy-hook POST in `vercel-rebuild` only fires a webhook and
returns immediately, so its timeout is intentionally left unchanged.
- If 300s later proves tight, the next levers are raising server-side
extract concurrency (bounded by upstream raw-content rate limits) or
moving the whole-branch reindex to an async job. Out of scope here.

</details>

---
> Opened as a **draft** by Coder Agents on behalf of @nickvigilante.
2026-07-08 14:42:20 +00:00
Nick Vigilante 182bdc871a docs: scaffold docs/.style for the prose style guide (#25466)
Adds a private contributor-tooling directory at `docs/.style/` that will
host the canonical prose style guide and the custom Vale rules used to
enforce it. The directory's contents do not deploy to `coder.com/docs`.

This PR is the scaffold only. The Vale configuration, the rule set, and
the per-rule style-guide sections all land in follow-up PRs.

## What changes

- New `docs/.style/` directory with:
  - `README.md` explaining the convention
  - `style-guide.md` as a table-of-contents scaffold
- `styles/Coder/README.md` placeholder so Git tracks the empty Vale
rules dir
- `.github/workflows/deploy-docs.yaml`: skip the workflow on
`.style`-only pushes, and exclude `.style` paths from the
surgical-reindex git diff on mixed commits. Defense-in-depth on top of
the manifest-driven coder.com routing.
- `.github/.linkspector.yml`: add `docs/.style` to `excludedDirs`
- `AGENTS.md` and `.claude/docs/DOCS_STYLE_GUIDE.md`: cross-link to the
new style guide for agents

## Verification

- `make pre-commit-light` clean (`fmt/markdown`, `lint/markdown`,
`lint/typos`, `lint/emdash`, `lint/actions/actionlint`,
`lint/shellcheck`).
- `markdown-table-formatter --check` and `markdownlint-cli2` both
process the new files (existing globs are `find docs -name '*.md'`).
- `actionlint` clean on the modified workflow.
- coder.com exclusion works because route discovery and Algolia indexing
are manifest-driven; this directory is not in `docs/manifest.json`. The
workflow changes are defense in depth.

<details>
<summary>Implementation plan and decision log</summary>

### Decisions

- **Location**: `docs/.style/` (leading dot, mirrors `.github/`,
`.vscode/`, `.claude/`). Vale's `StylesPath` will be
`docs/.style/styles/`; `.vale.ini` lands at repo root in a follow-up.
- **Existing public page `docs/about/contributing/documentation.md`**:
untouched in this PR. Nick's separate information-architecture rework
will redirect it to GitHub at the right time.
- **Placeholder for empty `styles/Coder/`**: real `README.md`, not
`.gitkeep`. Discoverable on GitHub, lints with the existing tooling,
lists the planned starter rules.
- **CONTRIBUTING.md**: not touched. It's a 2-line redirect to
`coder.com/docs/CONTRIBUTING`; bloating it would defeat the redirect.
- **`.claude/docs/DOCS_STYLE_GUIDE.md`**: kept as the structure/research
companion. A blockquote at the top points at the new canonical prose
guide.

### coder.com exclusion mechanism (verified by inspection)

Direct inspection of `coder/coder.com`:

- Route discovery in
[`src/utils/docs/docs.ts`](https://github.com/coder/coder.com/blob/master/src/utils/docs/docs.ts)
iterates `routes` from `docs/manifest.json`. Files not in the manifest
never become routes.
- The Algolia surgical indexer at
[`src/utils/algoliaDocs/surgical.ts`](https://github.com/coder/coder.com/blob/master/src/utils/algoliaDocs/surgical.ts)
explicitly skips paths not in the manifest, incrementing `pathsSkipped`.

Net result: not adding anything from `docs/.style/` to `manifest.json`
is the only thing that has to be true for the exclusion to work. The
`deploy-docs.yaml` tweaks are defense in depth.

### deploy-docs.yaml changes (pre-mortem)

1. Trigger path negation `!docs/.style/**` skips the workflow on
`.style`-only pushes. GitHub Actions only suppresses when every changed
file matches a negation, so mixed commits still trigger.
2. The git-diff pathspec `:(exclude)docs/.style/**` drops `.style` paths
from the surgical-reindex payload on mixed commits.

Risks considered:

- **Test contract**: `.github/workflows/test-deploy-docs-diff.sh` only
exercises the downstream awk parser, not the git-diff invocation. The
exclusion happens at git-diff time; the parser sees the same
`<status>\0<path>\0` format. No test change needed.
- **First push to a brand-new branch**: the workflow falls back to
whole-branch reindex when `BEFORE_SHA` is all zeros. Whole-branch
reindex re-extracts records from the manifest, which still excludes
`.style` files because they are not in the manifest.
- **Workflow-dispatch**: takes the whole-branch path; same reasoning.
Safe.

### Why a real README in `styles/Coder/` instead of `.gitkeep`

It explains intent, lists the upcoming rules, and lints with the
existing tooling. The cost is one extra Markdown file; the upside is
that a contributor browsing GitHub sees the plan without clicking
around.

</details>

---

*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*


Linear: DOCS-180
2026-06-17 13:19:37 +00:00
Nick Vigilante fb24110933 feat(.github/workflows): trigger docs reindex on release.published (DOCS-327) (#26070)
Closes
[DOCS-327](https://linear.app/codercom/issue/DOCS-327/trigger-docs-reindex-on-codercoder-releasepublished).

## What

Add `release: { types: [published] }` to
`.github/workflows/deploy-docs.yaml` so that publishing a stable
`vX.Y.Z` GitHub Release on this repo auto-dispatches the docs-sync
handler against the corresponding `release/X.Y` branch. The existing
`push` and `workflow_dispatch` triggers are unchanged.

The `Compute action and ref` step gains a release-event branch that:

- Skips prereleases (`github.event.release.prerelease == true`) with a
workflow notice.
- Matches the tag against `^v([0-9]+)\.([0-9]+)\.[0-9]+$` and translates
`v2.35.0` to `release/2.35`.
- Falls through with a notice and `exit 0` for any tag that doesn't
match the plain semver shape (`v2.35`, `v2.35.0-rc.1`, etc.).

Downstream validation, HMAC body construction, and the POST step are
unchanged. The POST step gains an `if: steps.input.outputs.action != ''`
guard so the two `exit 0` paths skip the POST instead of sending empty
`action`/`ref` to the production handler.

A new `.github/workflows/test-deploy-docs-release.sh` exercises the
release-event bash against the 11 event scenarios in the table below
plus 3 regex boundary cases, mirroring the existing
`test-deploy-docs-diff.sh` pattern.

## Why

Today, every mainline rollover requires a human to dispatch this
workflow manually with `action=index, ref=release/X.Y`. We just hit this
rotation friction on
[DOCS-324](https://linear.app/codercom/issue/DOCS-324/rotate-algolia-indexer-allowlist-for-v234-launch-add-release234-drop)
(v2.34 launch) and the resulting empty-search-results incident on
`/docs/@v2.34.x/...`. `release.published` is the right cue: it fires
exactly when a version becomes user-visible, not when its release branch
is cut weeks earlier with possibly-incomplete docs.

## Coupling (important)

This change is **intentionally inert until coder.com's
`INDEXED_REFS_BY_CORPUS` allowlist becomes self-rotating** (filed under
[DOCS-210](https://linear.app/codercom/issue/DOCS-210/automated-docs-index-lifecycle-management)).
Until that lands, the handler still rejects new minors with `{action:
"skipped", reason: "...not in INDEXED_REFS_BY_CORPUS"}` and this
workflow logs the skip. Pre-wiring lets both halves land roughly in
parallel so the next release cut after both ship is automatic.

Reviewers: feel free to merge this independently. There is no downside
to the wiring being live before the allowlist half ships; worst case,
every release-publish event creates a no-op workflow run.

## Behavior trace (the cases the bash handles)

<details>
<summary>11 event scenarios I walked through by hand</summary>

| Event | Tag | prerelease | Result |
|---|---|---|---|
| push to main | n/a | n/a | `index`, `ref=main` (existing) |
| push to release/2.34 | n/a | n/a | `index`, `ref=release/2.34`
(existing) |
| workflow_dispatch index release/2.34 | n/a | n/a | `index`,
`ref=release/2.34` (existing) |
| workflow_dispatch delete release/2.31 | n/a | n/a | `delete`,
`ref=release/2.31` (existing) |
| release.published | `v2.35.0` | `false` | `index`, `ref=release/2.35`
(new) |
| release.published | `v2.35.0-rc.1` | `true` | notice + `exit 0` (new)
|
| release.published | `v2.35.0-rc.1` | `false` | notice + `exit 0`,
regex miss (new) |
| release.published | `v2.35` | `false` | notice + `exit 0`, regex miss
(new) |
| release.published | `release-2.35` | `false` | notice + `exit 0`,
regex miss (new) |
| release.published | `v0.0.0` | `false` | `index`, `ref=release/0.0`
then handler rejects via allowlist (defense in depth) |
| release.published | `` (empty) | unset | notice with `<unknown>` +
`exit 0` |

</details>

## Safety

- The handler's allowlist gate still applies; this PR can only cause
`{action: "skipped"}` responses until DOCS-210's allowlist-derivation
lands. No risk of indexing an unintended ref.
- The workflow's existing input validation (`case "$REF" in
main|release/*)`) rejects any translation output that isn't
`release/<int>.<int>`. Defense in depth in case the regex ever loosens
by accident.
-
[DOCS-121](https://linear.app/codercom/issue/DOCS-121/post-mortem-docs-search-outage-2026-05-12-pr-25049-merge-wiped-docs)
self-trigger risk is not present here: the new trigger is
`release.published`, not push-on-paths. Workflow file edits cannot
induce a release event.
- `concurrency: { group: deploy-docs-${{ github.ref }} }` already
exists. Release events have `github.ref=refs/tags/vX.Y.Z`, distinct from
push events on the same release branch. A theoretical race resolves
through the handler's atomic deleteBy+saveObjects.
- The POST step now has an `if:` guard that skips downstream calls when
the Compute step exits early without writing outputs. Closes the
empty-env-var failure mode that coder-agents-review CRF-1 flagged.

## Verification

- `actionlint .github/workflows/deploy-docs.yaml` clean.
- `make pre-commit-light` clean: `fmt/shfmt`, `fmt/markdown`,
`lint/actions/actionlint`, `lint/shellcheck`, `lint/markdown`,
`lint/emdash`, `lint/typos`, etc.
- `.github/workflows/test-deploy-docs-release.sh`: 14 cases pass (11
scenario table + 3 regex boundary cases).
- Bash logic hand-traced through 11 event scenarios (table above).

## Out of scope

- Build-time allowlist derivation in coder.com (DOCS-210a, will be
filed/PR'd as a sibling change).
- Webhook-driven cleanup of aged-out refs
([DOCS-210](https://linear.app/codercom/issue/DOCS-210) parent).
- code-server release lifecycle (different repo, code-server's docs
corpus stays at `main`).

---

_Coder Agents on behalf of @nickvigilante._
2026-06-12 17:54:32 -04:00
Nick Vigilante 81b6132e02 fix(.github/workflows/deploy-docs.yaml): drop self-trigger from paths (#25285)
Edits to `.github/workflows/deploy-docs.yaml` previously self-triggered
the workflow on push to `main` and `release/*` because the file was
listed in its own `paths:`. On 2026-05-12, this caused merge of #25049
to fire a production reindex with no `docs/**` changes, which entered
the empty-`paths_json` whole-branch path in the Algolia handler and
wiped the `docs` index (see DOCS-121).

This change removes `.github/workflows/deploy-docs.yaml` from `paths:`
so the workflow only runs against real docs content. Reindexes from a
workflow edit alone now require `workflow_dispatch`, which already
accepts a `ref` input and an `action` choice of `index` or `delete`. The
other safety net (a workflow-level `paths_json=[]` guard in
`algolia-and-isr`) is tracked separately in DOCS-122.

Refs DOCS-121, DOCS-122, DOCS-124.

---
_Coder Agents on behalf of @nickvigilante._
2026-05-15 08:48:48 -04:00
Nick Vigilante 36d52ba504 feat(.github/workflows): trigger Algolia, ISR, and Vercel deploy on docs/** changes (#25049)
Folds the Algolia/ISR sync trigger and surgical-reindex path computation
into the existing `deploy-docs.yaml` workflow so a single `docs/**` push
fires every update path the docs site needs.

One preflight job feeds two parallel sibling jobs:

- **`changes`** (preflight): diffs `github.event.before` against
`github.sha` to compute `manifest_changed` and `paths_json` (a JSON
array of `{path, status}` objects derived from `git diff --name-status
-z`, capped at 50 entries). The mapping is `A → added`, `M/T →
modified`, `D → deleted`, `R<n> → renamed` (indexed by the new path).
Falls back to whole-branch (emits `paths_json: "[]"`) on
`workflow_dispatch`, the first push to a new branch, fetch failure,
manifest changes (route restructuring would orphan records), or >50
markdown files.
- **`algolia-and-isr`** (always, parallel with `vercel-rebuild`):
HMAC-signed POST to `coder.com/api/algolia-docs-sync` with the
`paths_json` array as part of the body. Refreshes the Algolia `docs`
slice for the `(corpus, ref)` pair and ISR-revalidates every navigable
route the handler touched. Markdown-only edits surface in seconds with
no full rebuild. The step summary line `Mode: \`surgical\` (N path(s))`
lets operators verify which path ran without scrolling through the curl
output.
- **`vercel-rebuild`** (parallel with `algolia-and-isr`, only when
`docs/manifest.json` changed): fires the existing Vercel deploy hook for
a full build. Manifest changes can register or remove routes that
Next.js's `getStaticPaths` only re-evaluates on a full build, so
ISR-per-existing-path is not enough.

Trigger expanded from "main + manifest.json" to "main and `release/*` +
any `docs/**`" so release-branch docs edits also flow through the same
pipeline. The Vercel rebuild path stays gated on manifest changes
regardless of branch.

The pure shell + curl + openssl + jq + awk pipeline is preserved
verbatim. Zero Algolia or Node dependencies in CI.

## Why one workflow instead of two

The original split (a standalone Algolia workflow + the existing
`deploy-docs.yaml`) would have run twice per manifest push, with two
parallel concurrency groups, two GitHub Actions step summaries, and two
ways to forget to add a secret. Folding into one file makes the trigger
story symmetrical: "docs change → all docs surfaces refresh," with the
rebuild path being a strict superset of the ISR path, and the surgical
path strictly cheaper than whole-branch when computable.

## Pre-merge testing

The companion handler PR (coder/coder.com#741) supports an
`ALGOLIA_DOCS_INDEX` env-var override, scoped to `docs_smoke` on the
Vercel preview deploy, so this workflow can be exercised end-to-end
against a disposable index without touching production records. The
smoke harness at `~/audit/smoke/run.sh` (workspace-only) signs and posts
the same body shape this workflow does, so it covers the same crypto
path. To exercise the workflow itself, push a docs-only commit to a
throwaway branch and watch the step summary; the `algolia-and-isr` job
will print the resolved mode.

## Prerequisites before this can do anything useful

1. `secrets.ALGOLIA_DOCS_SYNC_SECRET` must be added as an Actions secret
on this repo. The same value goes on `coder.com`'s Vercel env. The
workflow logs a clear error and aborts with no network call if the
secret is missing.
2. The handler at coder/coder.com#741 must be merged and deployed.
Without it, the POST will 404.
3. `secrets.DEPLOY_DOCS_VERCEL_WEBHOOK` is already in place from the
existing `deploy-docs.yaml`; this PR does not change its usage.

## Demo, validation, and design

- Front-end-only fixes (modal layout, scroll-shadow, rank-order
preservation): coder/coder.com#749 ships these against production today,
independent of this PR.
- Companion handler PR on `coder.com`: coder/coder.com#741. Includes the
surgical-mode plumbing this workflow's `paths_json` output drives.
- Full design lives in the workspace at
`~/plans/algolia-search-revamp.md`. Key sections:
  - §6.0–6.2: why the indexer lives in `coder.com`, not here.
  - §6.7: per-version add/remove mechanics.
  - §6.8: ISR revalidate rationale and same-time refresh.
- §6.9: surgical per-page reindex (workflow + handler + planning rules).

---

This PR was generated by Coder Agents.
2026-05-12 14:18:31 -04:00
Ethan e738ff5299 ci: remove dylib build pipeline (#22592)
## Summary

The macOS `.dylib` is only used by Coder Desktop macOS v0.7.2 or older.
v0.7.2 was released in August 2025. v0.8.0 of Coder Desktop macOS, also
released in August 2025, uses a signed Coder slim binary from the
deployment instead.

It's unlikely customers will be using Coder Desktop macOS v0.7.2 and the
next release of Coder simultaneously, so I think we can safely remove
this process, given it slows down CI & release processes.

## Changes

- **Makefile**: Remove `DYLIB_ARCHES`, `CODER_DYLIBS` variables and
`build/coder-dylib` target
- **scripts/build_go.sh**: Remove `--dylib` flag and all dylib-specific
logic (c-shared buildmode, CGO, plist embedding, vpn/dylib entrypoint)
- **scripts/sign_darwin.sh**: Remove dylib-specific comment
- **CI (ci.yaml)**: Remove `build-dylib` job, artifact download/insert
steps, and `build-dylib` dependency from `build` job
- **Release (release.yaml)**: Remove `build-dylib` job, artifact
download/insert steps, and `build-dylib` dependency from `release` job
- **vpn/dylib/**: Delete entire directory (`lib.go` + `info.plist.tmpl`)
- **vpn/router.go, vpn/dns.go**: Clean up comments referencing dylib

The slim and fat binary builds are completely unaffected — the dylib was
an independent build target with its own CI job.

_Generated by mux but reviewed by a human_
2026-03-05 01:50:50 +11:00
Andrew Aquino ef2e408c0c chore: add GitHub Action to build+deploy coder.com whenever docs paths change (#22283)
## problem

Fixes an issue where updates to docs resulted in docs links returning
HTTP 404, sometimes taking 4-12 hours before returning HTTP 200 (OK).

coder.com is deployed to Vercel from a separate Next.js repo, which has
no knowledge of when docs pages in this repo get updated.

### examples (non-exhaustive)

PR | 404 description
---|---
#19625 | URL for https://coder.com/docs/install/offline was updated to
https://coder.com/docs/install/airgap, but the latter returned 404 for 3
hr 56 min after the PR was merged
#21434 | URLs https://coder.com/docs/ai-coder/nsjail and
https://coder.com/docs/ai-coder/landjail were added, but both paths
404ed for 1 hr 30 min after the PR was merged. Note that these paths
have changed since then--don't be alarmed if clicking those links
returns 404s while reviewing this PR
#21708 | URL https://coder.com/docs/ai-coder/boundary/agent-boundary was
added, but it returned 404 for 1 hr 19 min after the PR was merged

## solution

All 3 PRs listed above modify manifest.json. This file is fetched during
coder.com's `getStaticPaths` for docs pages, defining which docs URLs
get statically generated at build time. In the latter 2 cases, the 404s
were resolved by manually triggering a redeploy of coder.com in the
Vercel dashboard.

The new CI workflow in this PR automatically triggers a Vercel deploy
hook ([see
docs](https://vercel.com/docs/deploy-hooks#triggering-a-deploy-hook))
with a POST request that runs whenever commits are pushed to main that
modify manifest.json. The deploy hook initiates a new build+deploy of
the coder.com Next.js app, which reruns `getStaticPaths`, updating docs
pages' URLs.

**Note:** I have not tested this workflow yet. I will verify that it
works after this PR is merged. I confirmed in a local terminal that the
webhook URL does successfully initiate a new Vercel build. I also tested
with a malformed URL and received error JSON output, so if the action
fails for some reason, we should see error output in the workflow logs
([example](https://github.com/coder/coder/actions/runs/22361453442/job/64722503802)).
2026-03-03 00:38:49 -08:00