refactor(docs): convert absolute coder/coder blob/tree/main links to relative (DOCS-351) (#26341)

Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351).

> [!WARNING]
> **DO NOT MERGE** until
[DOCS-349](https://linear.app/codercom/issue/DOCS-349)
([coder.com#877](https://github.com/coder/coder.com/pull/877)) has
shipped to production and baked for at least one Vercel cycle.
>
> Without DOCS-349, the relative links in this PR resolve to broken
docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of
GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the
rewriter to classify these as GitHub blob/tree URLs with the page's
resolved ref.

## TL;DR

Converts 121 absolute
`https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39
docs markdown files to relative paths. After this lands AND DOCS-349
deploys, every one of these links will follow the displayed docs version
(mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on
`/@main/`) instead of always pointing to `main`.

## Why

Today a reader on `/docs/@v2.30.0/install/docker` follows a
`compose.yaml` link and arrives at `main`'s `compose.yaml`, which
doesn't necessarily match what the docs page describes. Helm values,
Terraform templates, and source-code references in particular drift
across versions. The fix is to let the coder.com rewriter substitute the
page's resolved ref into the URL; that only works on relative links.

## Example payoff (post-DOCS-349)

| URL | Today (absolute, always `main`) | After (relative + rewriter) |
|---|---|---|
| `/docs/install/docker` |
`https://github.com/coder/coder/blob/main/compose.yaml` |
`https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's
mainline) |
| `/docs/@v2.30.0/install/docker` | same as above |
`https://github.com/coder/coder/blob/v2.30.0/compose.yaml` |
| `/docs/@main/install/docker` | same as above |
`https://github.com/coder/coder/blob/main/compose.yaml` |

## Scope

- **121 conversions** across **39 files**.
- Verb breakdown: `tree/main` (directories) and `blob/main` (files),
both flipped to relative paths.
- Line anchors (`#L23-L24`) and query strings preserved verbatim.
- Conversion is mechanical: relative path computed from the doc file's
directory to the target via `os.path.relpath`. Any path starting at the
same directory or below gets a `./` prefix; otherwise `../` chains.

## Rebased on main

The branch was rebased onto `main` after the DOCS-350 hotfix
([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix
repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`,
which then needed the same `main` -> relative conversion this PR is
doing for the other 121 links. The conflict was resolved by reapplying
the mechanical conversion to `backend.md` after taking the hotfix's
content. Net result: those 3 links land here as relative, same as
everything else. New HEAD `3f501cb622`.

## Inline fix folded in: dead `nix` link

- `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix`

The original absolute URL `https://github.com/coder/coder/tree/main/nix`
already returned 404 today. Repointed to `flake.nix` (modern Nix
entrypoint, what the prose "Nix environment" semantically refers to).
Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since
the `check-docs` Linkspector job surfaced it during rebase; cheaper to
fix inline than in a separate single-line PR.

## Out of scope (filed separately)

- [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead
`docs-backend-contrib-guide` branch refs in `backend.md`
([#26339](https://github.com/coder/coder/pull/26339), merged).
- [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned
`(blob|tree)/<sha>` links pending intent review.
- [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server
analog (4 absolute `(blob|tree)/main` links in `coder/code-server`).
- [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream
content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of
this PR).


## Not triggering `/coder-agents-review`

Docs-only edit; per `AGENTS.md` the bot review is reserved for
product/CI changes.

## Pre-mortem

| Concern | Mitigation |
|---|---|
| Merging before DOCS-349 deploys regresses ~120 currently-working links
into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker
in Linear. |
| Relative path computed incorrectly (off-by-one `..`) | Verified all
114 newly-relative non-md/non-image paths resolve to existing files in
the repo (only exception is the pre-existing dead `nix` link above). |
| Line anchors stripped during conversion | Preserved by the
substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and
`speed-up-templates.md`. |
| Future code reorgs change file locations | Relative links will start
pointing to nothing. Same failure mode as absolute links pointing to
renamed files; can be caught with a future link-checker job. |

## Validation

```
$ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l
0
$ git diff --stat origin/main | tail -1
39 files changed, 118 insertions(+), 118 deletions(-)
```

114 newly-relative paths verified to resolve to existing repo files
(Python `os.path.exists` check on each computed target).

<details>
<summary>Decision log + planning context</summary>

**Why relative over `(blob|tree)/{{currentDocsVersion}}/...`
templating**: relative paths require zero markdown-system support and
zero upstream churn beyond this one PR. Templating would require a
preprocessor on `coder.com` side AND a convention upstream authors have
to remember; relative paths just work in a plain editor and
`github.com`'s own renderer too.

**Why `./` prefix on same-directory targets**: makes the conversion
grep-able later (`grep -E '\((\.\./|\./)'`).

**Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful
to the linked file's content, not to the URL form; keeping it as-is
preserves authorial intent. If the file later changes such that the line
range drifts, that's a different problem the SHA-pin audit
([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface.

</details>

---

*Generated by Coder Agents on @nickvigilante's behalf.*





## Drive-by external link fix folded in

`docs/about/contributing/CONTRIBUTING.md:296` cited
`https://reflectoring.io/meaningful-commit-messages/` which is returning
HTTP 503 (the host appears to be down site-wide right now). `check-docs`
Linkspector flagged it after the rebase. Replaced with
`https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this
commit will..." article, confirmed 200), which is the original source of
the rule the prose recites anyway.
This commit is contained in:
Nick Vigilante
2026-06-22 11:39:12 -04:00
committed by GitHub
parent 46916bf899
commit e458692cb8
39 changed files with 119 additions and 119 deletions
+5 -5
View File
@@ -6,7 +6,7 @@ air-gapped with Kubernetes or Docker.
| | Public deployments | Air-gapped deployments |
|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Terraform binary | By default, Coder downloads Terraform binary from [releases.hashicorp.com](https://releases.hashicorp.com) | Terraform binary must be included in `PATH` for the VM or container image. [Supported versions](https://github.com/coder/coder/blob/main/provisioner/terraform/install.go#L23-L24) |
| Terraform binary | By default, Coder downloads Terraform binary from [releases.hashicorp.com](https://releases.hashicorp.com) | Terraform binary must be included in `PATH` for the VM or container image. [Supported versions](../../provisioner/terraform/install.go#L23-L24) |
| Terraform registry | Coder templates will attempt to download providers from [registry.terraform.io](https://registry.terraform.io) or [custom source addresses](https://developer.hashicorp.com/terraform/language/providers/requirements#source-addresses) specified in each template | [Custom source addresses](https://developer.hashicorp.com/terraform/language/providers/requirements#source-addresses) can be specified in each Coder template, or a custom registry/mirror can be used. More details below |
| STUN | By default, Coder uses Google's public STUN server for direct workspace connections | STUN can be safely [disabled](../reference/cli/server.md#--derp-server-stun-addresses) users can still connect via [relayed connections](../admin/networking/index.md#-geo-distribution). Alternatively, you can set a [custom DERP server](../reference/cli/server.md#--derp-server-stun-addresses) |
| DERP | By default, Coder's built-in DERP relay can be used, or [Tailscale's public relays](../admin/networking/index.md#relayed-connections). | By default, Coder's built-in DERP relay can be used, or [custom relays](../admin/networking/index.md#custom-relays). |
@@ -33,7 +33,7 @@ following:
> [!NOTE]
> Coder includes the latest
> [supported version](https://github.com/coder/coder/blob/main/provisioner/terraform/install.go#L23-L24)
> [supported version](../../provisioner/terraform/install.go#L23-L24)
> of Terraform in the official Docker images. If you need to bundle a different
> version of terraform, you can do so by customizing the image.
@@ -50,10 +50,10 @@ RUN apk add curl unzip
RUN mkdir -p /opt/terraform
# Terraform is already included in the official Coder image.
# See https://github.com/coder/coder/blob/main/scripts/Dockerfile.base#L15
# See ../../scripts/Dockerfile.base#L15
# If you need to install a different version of Terraform, you can do so here.
# The below step is optional if you wish to keep the existing version.
# See https://github.com/coder/coder/blob/main/provisioner/terraform/install.go#L23-L24
# See ../../provisioner/terraform/install.go#L23-L24
# for supported Terraform versions.
ARG TERRAFORM_VERSION=1.11.0
RUN apk update && \
@@ -115,7 +115,7 @@ ENV TF_CLI_CONFIG_FILE=/home/coder/.terraformrc
> [!NOTE]
> If you are bundling Terraform providers into your Coder image, be sure the
> provider version matches any templates or
> [example templates](https://github.com/coder/coder/tree/main/examples/templates)
> [example templates](../../examples/templates)
> you intend to use.
```tf
+3 -3
View File
@@ -29,7 +29,7 @@ deployments and you should adjust your infrastructure when preparing for
production use. See: [Scaling Coder](../../admin/infrastructure/index.md)
<video autoplay playsinline loop>
<source src="https://github.com/coder/coder/blob/main/docs/images/platforms/gcp/launch.mp4?raw=true" type="video/mp4">
<source src="../../images/platforms/gcp/launch.mp4?raw=true" type="video/mp4">
Your browser does not support the video tag.
</video>
@@ -65,12 +65,12 @@ sudo systemctl restart coder # restart Coder
Instead of running containers on the Coder instance, you can offer developers
full VM instances with the
[gcp-linux](https://github.com/coder/coder/tree/main/examples/templates/gcp-linux)
[gcp-linux](../../../examples/templates/gcp-linux)
template.
Before you can use this template, you must authorize Coder to create VM
instances in your GCP project. Follow the instructions in the
[gcp-linux template README](https://github.com/coder/coder/tree/main/examples/templates/gcp-linux#authentication)
[gcp-linux template README](../../../examples/templates/gcp-linux#authentication)
to set up authentication.
### Next Steps
+2 -2
View File
@@ -23,14 +23,14 @@ You can install and run Coder using the official Docker images published on
## Install Coder via `docker compose`
Coder publishes a
[docker compose example](https://github.com/coder/coder/blob/main/compose.yaml)
[docker compose example](../../compose.yaml)
which includes a PostgreSQL container and volume.
1. Make sure you have [Docker Compose](https://docs.docker.com/compose/install/)
installed.
1. Download the
[`docker-compose.yaml`](https://github.com/coder/coder/blob/main/compose.yaml)
[`docker-compose.yaml`](../../compose.yaml)
file.
1. Update `group_add:` in `docker-compose.yaml` with the `gid` of `docker`
+2 -2
View File
@@ -118,9 +118,9 @@ coder:
```
You can view our
[Helm README](https://github.com/coder/coder/blob/main/helm/coder#readme) for
[Helm README](../../helm/coder#readme) for
details on the values that are available, or you can view the
[values.yaml](https://github.com/coder/coder/blob/main/helm/coder/values.yaml)
[values.yaml](../../helm/coder/values.yaml)
file directly.
We support two release channels: mainline and stable - read the
+2 -2
View File
@@ -127,8 +127,8 @@ kubectl create secret generic coder-db-url -n coder \
# - my-tls-secret-name
```
For available configuration options, refer to the [Helm chart documentation](https://github.com/coder/coder/blob/main/helm#readme)
or [values.yaml file](https://github.com/coder/coder/blob/main/helm/coder/values.yaml).
For available configuration options, refer to the [Helm chart documentation](../../helm#readme)
or [values.yaml file](../../helm/coder/values.yaml).
</details>
+1 -1
View File
@@ -172,7 +172,7 @@ If an upgrade gets stuck in a restart loop due to database locks:
1. **Ensure image version:** Confirm the Deployment image is set to the
appropriate version (old or new, depending on the database migration state
found in step 3). Match your tag in the
[migrations directory](https://github.com/coder/coder/tree/main/coderd/database/migrations)
[migrations directory](../../coderd/database/migrations)
to the value in the `schema_migrations` output.
1. **Resume the upgrade:** Follow the