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
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ tests/esmini/*.xosc text eol=lf
# reads in binary, so without this the Windows runner's autocrlf checkout would
# fail the gate on line endings alone.
core/tests/data/junction/straight_floor_golden.txt text eol=lf

# Fourth instance (#563): the site's Starlight palette is what
# help_style::starlight_css() emits, compared byte for byte by
# StarlightCssMatchesCommittedThemeCss. The generator writes '\n' and the test
# reads in binary, so without this the Windows runner's autocrlf checkout fails
# the gate on line endings alone.
docs-site/src/styles/theme.css text eol=lf
7 changes: 0 additions & 7 deletions .github/workflows/docs-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@ jobs:
- name: Internal links
run: npm run check:links

# Report only, on purpose: link rot in a third party's URL is not a reason
# a contributor's merge cannot happen. `continue-on-error` as well as the
# script's own exit 0, so a crash in the reporter cannot block either.
- name: Outbound link report (never blocks)
continue-on-error: true
run: npm run report:external

- uses: actions/upload-artifact@v4
with:
name: docs-site
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/external-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: external links

# Reports outbound links that have rotted. Replaces docs-site's hand-rolled
# report-external-links.mjs (#563), which was 125 lines of fetch, concurrency
# and timeout handling to produce a report that always exited 0 — all of it
# already in the lychee action ci.yml runs `--offline` on the PR path.
#
# WHY A SEPARATE WORKFLOW AND NOT A JOB IN ci.yml: adding `schedule` there would
# arm all fourteen of its jobs, and gating each one is a worse diff than this
# file. It also keeps the network-touching check off the PR path entirely.
#
# DELIBERATELY NON-BLOCKING (`fail: false`). A third party rearranging their
# site, or rate-limiting a runner, is not a reason a contributor's merge cannot
# happen — and a gate that fails for reasons nobody in this repository can fix
# is a gate people learn to ignore, which costs more than the link rot it was
# meant to catch. Read the summary; it is a report, not a status to satisfy.

on:
schedule:
- cron: '17 6 * * 1' # Mondays, 06:17 UTC
workflow_dispatch:

permissions:
contents: read

jobs:
external-links:
name: outbound link report (never blocks)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

# No --offline, so external URLs ARE fetched here — the one place they
# are. The PR-path `docs` job in ci.yml keeps --offline and stays
# deterministic.
- name: Check outbound links
uses: lycheeverse/lychee-action@v2
with:
args: >-
--no-progress
--max-concurrency 8
--timeout 15
--accept 200,206,429
"docs/**/*.md"
"*.md"
fail: false
output: lychee-report.md

- name: Publish the report to the run summary
if: always()
run: cat lychee-report.md >> "$GITHUB_STEP_SUMMARY" || true
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,22 @@ Current version on `main`: **0.0.1**.
`append_fragment` was NOT shared despite the identical name and shape — the
OpenSCENARIO writer passes `pugi::parse_fragment` and the OpenDRIVE one does
not, so that pair is a real divergence and stays per-format.
- **The documentation site stops parsing C++ source, and outbound links move to
lychee** ([#563](https://github.com/Robomous/RoadMaker/issues/563)).
`docs-site/scripts/theme-css.mjs` located `graphite_amber()` inside
`theme.cpp` with `indexOf` and regexed the `QColor(0x..)` literals back out —
a JavaScript parser of C++ source that any reformat of `theme.cpp` breaks. The
palette is now emitted by `help_style::starlight_css()`, beside the in-app
`help.css` generator it copies, and `docs-site/src/styles/theme.css` is
committed and byte-gated by a gtest. Every colour is unchanged. The site build
still needs nothing but Node (ADR-0009): the gate runs in the C++ matrix and
the site just reads a committed file.

`docs-site/scripts/report-external-links.mjs` is gone too — 125 lines of
hand-rolled `fetch`, concurrency and timeout handling for a report that always
exited 0, when lychee was already a CI dependency. A weekly non-blocking
`external-links` workflow replaces it; it stays off the PR path, so a third
party's outage still cannot block a merge.
- **New roads default to the urban-with-sidewalks template**
([#355](https://github.com/Robomous/RoadMaker/issues/355)): the Create Road
tool, its toolbar dropdown, and the Library fallback now start from
Expand Down
8 changes: 6 additions & 2 deletions docs-site/.gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Adapted content is generated by scripts/adapt.mjs — never committed, never
# hand-edited. Same for the theme CSS, which is derived from theme.cpp.
# hand-edited.
#
# src/styles/theme.css is NOT here: it is generated by
# help_style::starlight_css() and COMMITTED, byte-gated by the
# StarlightCssMatchesCommittedThemeCss gtest (#563), so the Node-only site build
# never needs a C++ toolchain to produce it.
src/content/docs/
src/styles/theme.css
public/
node_modules/
dist/
Expand Down
25 changes: 19 additions & 6 deletions docs-site/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,30 @@ Astro Starlight project that publishes `docs/user-guide/` as a static site

## The content here is GENERATED — never hand-edit it

`src/content/docs/` and `src/styles/theme.css` are build outputs and are
gitignored. The sources are:
`src/content/docs/` is a build output and is gitignored. `src/styles/theme.css`
is generated too, but it is **committed** — see below. The sources are:

| Output | Source | Generator |
|---|---|---|
| `src/content/docs/**` | `docs/user-guide/**` | `scripts/adapt.mjs` |
| `src/styles/theme.css` | `editor/src/theme/theme.cpp` | `scripts/theme-css.mjs` |
| Output | Source | Generator | Committed? |
|---|---|---|---|
| `src/content/docs/**` | `docs/user-guide/**` | `scripts/adapt.mjs` | no, gitignored |
| `src/styles/theme.css` | `editor/src/theme/theme.cpp` | `help_style::starlight_css()` (C++) | **yes**, byte-gated |

Editing a generated file silently loses the edit on the next build. Change the
source instead.

**Why the palette is generated by C++ and committed** (#563). It used to be
produced by `scripts/theme-css.mjs`, which located `graphite_amber()` inside
`theme.cpp` with `indexOf` and regexed the `QColor(0x..)` literals back out — a
JavaScript parser of C++ source, which any reformat of `theme.cpp` breaks. It is
now emitted by `help_style::starlight_css()` beside the in-app `help.css`
generator, and the committed file is compared byte-for-byte against it by the
`HelpStyle.StarlightCssMatchesCommittedThemeCss` gtest.

That gate runs in the C++ CI matrix, so **the site build still needs nothing but
Node** (ADR-0009) — it just reads a file that is already in the tree. To change
the palette: edit `theme.cpp`, run the editor tests, and paste the new file the
failing gate prints.

## The two pipelines share one manifest

`docs/user-guide/index.md` is the ordering manifest for **both** the in-app Qt
Expand Down
8 changes: 3 additions & 5 deletions docs-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,16 @@
},
"scripts": {
"adapt": "node scripts/adapt.mjs",
"theme": "node scripts/theme-css.mjs",
"build": "npm run theme && npm run adapt && node scripts/check-f1-coverage.mjs && astro build",
"build": "npm run adapt && node scripts/check-f1-coverage.mjs && astro build",
"build:local": "node scripts/build-local.mjs",
"build:web": "node scripts/build-web.mjs",
"assemble": "node scripts/assemble.mjs",
"dev": "npm run theme && npm run adapt && astro dev",
"dev": "npm run adapt && astro dev",
"licenses": "node scripts/licenses.mjs",
"check": "node scripts/check-f1-coverage.mjs",
"check:local": "node scripts/check-local-build.mjs",
"test": "node --test \"test/**/*.test.mjs\"",
"check:links": "node scripts/check-links.mjs",
"report:external": "node scripts/report-external-links.mjs"
"check:links": "node scripts/check-links.mjs"
},
"dependencies": {
"@astrojs/starlight": "0.36.0",
Expand Down
1 change: 0 additions & 1 deletion docs-site/scripts/build-local.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ function step(label, command, args) {
const node = process.execPath;
const astro = join(root, 'node_modules', 'astro', 'astro.js');

step('theme tokens', node, [join(here, 'theme-css.mjs')]);
step('adapt docs/user-guide', node, [join(here, 'adapt.mjs')]);
step('F1 coverage', node, [join(here, 'check-f1-coverage.mjs')]);
step('astro build (file format, search off)', node, [astro, 'build']);
Expand Down
1 change: 0 additions & 1 deletion docs-site/scripts/build-web.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ function step(label, args) {
}
}

step('theme tokens', [join(here, 'theme-css.mjs')]);
step('adapt docs/user-guide', [join(here, 'adapt.mjs')]);
step('F1 coverage', [join(here, 'check-f1-coverage.mjs')]);
step('astro build', [join(root, 'node_modules', 'astro', 'astro.js'), 'build']);
Expand Down
4 changes: 2 additions & 2 deletions docs-site/scripts/check-links.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
// version directory that was published months ago and is still being served.
//
// EXTERNAL LINKS ARE NOT FETCHED HERE. Link rot in somebody else's URL is not a
// reason a merge cannot happen; report-external-links.mjs reports on those
// without failing anything.
// reason a merge cannot happen; the weekly `external-links` job in ci.yml
// reports on those without failing anything.
import { readFileSync, existsSync, statSync } from 'node:fs';
import { join, posix, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down
125 changes: 0 additions & 125 deletions docs-site/scripts/report-external-links.mjs

This file was deleted.

Loading
Loading