mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
docs: add redirects.json and rebuild the docs site when it changes (#30208)
This commit is contained in:
@@ -359,12 +359,12 @@ Don't manually edit auto-generated sections.
|
||||
|
||||
When renaming or moving documentation pages, redirects must be added to prevent broken links.
|
||||
|
||||
**Important**: Redirects are NOT configured in this repository. The coder.com website runs on Vercel with Next.js and reads redirects from a separate repository:
|
||||
Redirects are configured in `docs/redirects.json` in this repository. The coder.com website runs on Vercel with Next.js, reads the file at build time, and rebuilds when it changes.
|
||||
|
||||
- **Redirect configuration**: https://github.com/coder/coder.com/blob/master/redirects.json
|
||||
- **Redirect configuration**: `docs/redirects.json`, a JSON array of `{"source", "destination", "permanent"}` rules. Both paths are full `/docs/...` paths, `permanent` is optional and defaults to `true`, and a destination may be an external URL. A source is an exact path, a path ending in `/:path*`, or a path with a `:slug(.*)` capture.
|
||||
- **Do NOT create** a `docs/_redirects` file - this format (used by Netlify/Cloudflare Pages) is not processed by coder.com
|
||||
|
||||
When you rename or move a doc page, create a PR in coder/coder.com to add the redirect.
|
||||
When you rename or move a doc page, add the rule to `docs/redirects.json` in the same PR. Each release branch has its own copy, and the unversioned docs are served from the mainline release branch, so backport the move and its redirect together.
|
||||
|
||||
## Key Principles
|
||||
|
||||
@@ -375,4 +375,4 @@ When you rename or move a doc page, create a PR in coder/coder.com to add the re
|
||||
3. **Screenshots** - Include one only when the topic needs it; refer to [Screenshot policy](#screenshot-policy)
|
||||
4. **Link everything** - Related docs, API endpoints, CLI references
|
||||
5. **Manifest inclusion** - Add to `docs/manifest/` for navigation
|
||||
6. **Add redirects** - When moving/renaming pages, add redirects in coder/coder.com repo
|
||||
6. **Add redirects** - When moving/renaming pages, add a rule to `docs/redirects.json` in the same PR
|
||||
|
||||
@@ -299,13 +299,13 @@ violations it generates or suggests.
|
||||
### Renames and moves require redirects
|
||||
|
||||
Redirects for [coder.com/docs](https://coder.com/docs) are configured in
|
||||
a separate repo, not in this one. When a doc page is renamed or moved:
|
||||
`docs/redirects.json` in this repo, and the website rebuilds when the file
|
||||
changes. When a doc page is renamed or moved:
|
||||
|
||||
1. Update every link that relies on the old location.
|
||||
2. Add an entry to
|
||||
[`coder/coder.com:redirects.json`](https://github.com/coder/coder.com/blob/master/redirects.json)
|
||||
that maps the old path to the new one. Open that PR alongside the
|
||||
`coder/coder` rename PR.
|
||||
2. Add a rule to `docs/redirects.json` that maps the old path to the new
|
||||
one, in the same PR as the rename. For example:
|
||||
`{"source": "/docs/old/path", "destination": "/docs/new/path"}`.
|
||||
|
||||
Do not create a `docs/_redirects` file in this repo; that format isn't
|
||||
processed by coder.com.
|
||||
|
||||
@@ -146,8 +146,8 @@ application notes the canonical rules do not spell out:
|
||||
|
||||
- On a rename, pick the new link target by the specific page each sentence
|
||||
promises, not just the section hub, and confirm moved anchors still resolve.
|
||||
- Keep the redirect PR in `coder/coder.com` in sync with the rename PR so the
|
||||
old public path never 404s between merges.
|
||||
- Add the redirect to `docs/redirects.json` in the same PR as the rename so
|
||||
the old public path never 404s between merges.
|
||||
|
||||
## Keep PRs reviewable
|
||||
|
||||
@@ -198,7 +198,7 @@ the whole series as a single review.
|
||||
not as conformance: tooling covers a small subset of the guide, and Vale
|
||||
never fails a build. The count lives in
|
||||
[What the tooling checks, and what it doesn't](../../../docs/.style/style-guide/README.md#what-the-tooling-checks-and-what-it-doesnt).
|
||||
- [ ] Inbound links resolve; renames have redirects in `coder/coder.com`.
|
||||
- [ ] Inbound links resolve; renames have redirects in `docs/redirects.json`.
|
||||
- [ ] Premium pages carry the title suffix and manifest state.
|
||||
- [ ] Series pages orient the reader and link the next step; no dead-ends.
|
||||
- [ ] The change is scoped for review: large or multi-page work is split into
|
||||
|
||||
@@ -24,12 +24,14 @@ name: Update coder.com/docs
|
||||
# on every docs/** push.
|
||||
#
|
||||
# 2. vercel-rebuild: fires the Vercel deploy hook for a full
|
||||
# build+deploy. Only runs when docs/manifest.json changed, since a
|
||||
# manifest change can introduce or remove routes that Next.js's
|
||||
# `getStaticPaths` only re-evaluates on a full rebuild.
|
||||
# build+deploy. Only runs when docs/manifest.json or
|
||||
# docs/redirects.json changed. A manifest change can introduce or
|
||||
# remove routes that Next.js's `getStaticPaths` only re-evaluates on
|
||||
# a full rebuild, and the website reads docs/redirects.json at build
|
||||
# time, so a redirect only takes effect in a new build.
|
||||
#
|
||||
# Markdown-only edits hit only path 1 and surface in seconds. Manifest
|
||||
# edits hit both paths in parallel; the ISR revalidate is harmless
|
||||
# and redirects edits hit both paths in parallel; the ISR revalidate is harmless
|
||||
# against the previous deployment while the new build is in flight,
|
||||
# and Vercel only swaps to the new build atomically when ready.
|
||||
#
|
||||
@@ -92,11 +94,15 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
# Detect what changed so the dependent jobs know:
|
||||
# - whether a Vercel full rebuild is needed (manifest changed), and
|
||||
# - whether a Vercel full rebuild is needed (manifest or redirects
|
||||
# changed), and
|
||||
# - which markdown pages to surgically reindex (the changed set).
|
||||
#
|
||||
# Outputs:
|
||||
# manifest_changed: "true" | "false"
|
||||
# manifest_changed: "true" | "false"
|
||||
# redirects_changed: "true" | "false". Kept separate from
|
||||
# manifest_changed because it must not force the
|
||||
# whole-branch reindex a manifest change does.
|
||||
# paths_json: a JSON array of {path, status} objects, or "[]"
|
||||
# when no markdown changes are eligible for
|
||||
# surgical mode (manifest-only push, an
|
||||
@@ -109,6 +115,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
manifest_changed: ${{ steps.diff.outputs.manifest_changed }}
|
||||
redirects_changed: ${{ steps.diff.outputs.redirects_changed }}
|
||||
paths_json: ${{ steps.diff.outputs.paths_json }}
|
||||
steps:
|
||||
- name: Compute changed-files signal
|
||||
@@ -133,6 +140,7 @@ jobs:
|
||||
# resulting reindex is exhaustive.
|
||||
if [ "$EVENT_NAME" != "push" ]; then
|
||||
echo "manifest_changed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "redirects_changed=false" >> "$GITHUB_OUTPUT"
|
||||
emit_whole_branch_fallback
|
||||
exit 0
|
||||
fi
|
||||
@@ -142,6 +150,7 @@ jobs:
|
||||
# whole-branch reindex.
|
||||
if [ -z "${BEFORE_SHA:-}" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
|
||||
echo "manifest_changed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "redirects_changed=true" >> "$GITHUB_OUTPUT"
|
||||
emit_whole_branch_fallback
|
||||
exit 0
|
||||
fi
|
||||
@@ -160,9 +169,20 @@ jobs:
|
||||
FIRST_ERR=$(head -1 "$GIT_ERR" 2>/dev/null || true)
|
||||
echo "::warning::Could not fetch BEFORE_SHA=$BEFORE_SHA: ${FIRST_ERR:-unknown}; assuming manifest changed"
|
||||
echo "manifest_changed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "redirects_changed=true" >> "$GITHUB_OUTPUT"
|
||||
emit_whole_branch_fallback
|
||||
exit 0
|
||||
fi
|
||||
# Redirects signal. The website reads docs/redirects.json at build
|
||||
# time, so a change needs a full rebuild. Unlike the manifest it
|
||||
# cannot add or remove routes, so it leaves the surgical reindex
|
||||
# path below alone. Computed before the manifest signal so it is
|
||||
# set even when the manifest branch exits early.
|
||||
if git diff --name-only "$BEFORE_SHA" "$AFTER_SHA" -- docs/redirects.json | grep -q .; then
|
||||
echo "redirects_changed=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "redirects_changed=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
# Manifest signal.
|
||||
if git diff --name-only "$BEFORE_SHA" "$AFTER_SHA" -- docs/manifest.json | grep -q .; then
|
||||
echo "manifest_changed=true" >> "$GITHUB_OUTPUT"
|
||||
@@ -491,20 +511,30 @@ jobs:
|
||||
exit "$RC"
|
||||
fi
|
||||
|
||||
# Path 2: full Vercel rebuild. Only fires when docs/manifest.json
|
||||
# changed, because manifest changes can introduce or remove routes
|
||||
# that Next.js's `getStaticPaths` only re-evaluates on a full build.
|
||||
# Markdown-only edits don't need this; ISR revalidate covers them.
|
||||
# Path 2: full Vercel rebuild. Only fires when docs/manifest.json or
|
||||
# docs/redirects.json changed. Manifest changes can introduce or
|
||||
# remove routes that Next.js's `getStaticPaths` only re-evaluates on a
|
||||
# full build, and redirects are read at build time. Markdown-only
|
||||
# edits don't need this; ISR revalidate covers them.
|
||||
vercel-rebuild:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.manifest_changed == 'true'
|
||||
if: needs.changes.outputs.manifest_changed == 'true' || needs.changes.outputs.redirects_changed == 'true'
|
||||
steps:
|
||||
- name: Trigger Vercel deploy hook
|
||||
env:
|
||||
HOOK: ${{ secrets.DEPLOY_DOCS_VERCEL_WEBHOOK }}
|
||||
MANIFEST_CHANGED: ${{ needs.changes.outputs.manifest_changed }}
|
||||
REDIRECTS_CHANGED: ${{ needs.changes.outputs.redirects_changed }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
CHANGED_FILES=""
|
||||
if [ "${MANIFEST_CHANGED:-}" = "true" ]; then
|
||||
CHANGED_FILES="\`docs/manifest.json\`"
|
||||
fi
|
||||
if [ "${REDIRECTS_CHANGED:-}" = "true" ]; then
|
||||
CHANGED_FILES="${CHANGED_FILES:+$CHANGED_FILES and }\`docs/redirects.json\`"
|
||||
fi
|
||||
if [ -z "${HOOK:-}" ]; then
|
||||
echo "::error::DEPLOY_DOCS_VERCEL_WEBHOOK is not configured."
|
||||
exit 1
|
||||
@@ -537,7 +567,7 @@ jobs:
|
||||
{
|
||||
echo "## Vercel rebuild"
|
||||
echo
|
||||
echo "- Reason: \`docs/manifest.json\` changed"
|
||||
echo "- Reason: ${CHANGED_FILES} changed"
|
||||
echo "- HTTP status: \`${HTTP_STATUS:-n/a}\`"
|
||||
echo
|
||||
echo "### Response (allowlisted fields)"
|
||||
|
||||
@@ -243,9 +243,17 @@ These govern *how* content enters the docs, for both humans and the doc-check ag
|
||||
- **Moving or renaming a page requires link updates and a redirect.**
|
||||
If a page changes its position in the directory structure:
|
||||
1. Update every link that relies on its existing location.
|
||||
2. Add a redirect in the
|
||||
[`coder/coder.com`](https://github.com/coder/coder.com/blob/master/redirects.json)
|
||||
repo (`redirects.json`).
|
||||
2. Add a rule to `docs/redirects.json` in the same PR that moves the page.
|
||||
Each rule has a `source` and a `destination`, both full `/docs/...` paths, and an optional `permanent` flag that defaults to `true`.
|
||||
A `destination` can also be an external `http` or `https` URL.
|
||||
A `source` is an exact path, a path ending in `/:path*`, or a path with a `:slug(.*)` capture.
|
||||
For example: `{"source": "/docs/about/architecture", "destination": "/docs/about"}`.
|
||||
|
||||
The website reads `docs/redirects.json` at build time, and a change to the file starts a website rebuild.
|
||||
The redirect is therefore live in the build that the merge triggers.
|
||||
Each release branch has its own copy of the file, and the unversioned docs are served from the mainline release branch.
|
||||
Backport the move and its redirect together so the old URL keeps working there.
|
||||
Redirects that predate this file stay where they are and keep working.
|
||||
|
||||
Do not create a `docs/_redirects` file.
|
||||
That format isn't processed by [coder.com](https://coder.com).
|
||||
@@ -358,4 +366,4 @@ Update this section as they land.
|
||||
If it becomes real, revisit loosening the screenshots policy.
|
||||
Until then, the screenshot rules in [What belongs in the docs](#what-belongs-in-the-docs) govern.
|
||||
- **doc-check redirect suggestions.**
|
||||
When doc-check detects a moved or renamed page, it should suggest the exact `redirects.json` entry for `coder/coder.com` in a code block, so applying it is at most a copy-paste job.
|
||||
When doc-check detects a moved or renamed page, it should suggest the exact `docs/redirects.json` entry in a code block, so applying it is at most a copy-paste job.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
Reference in New Issue
Block a user