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
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,28 @@ jobs:
run: node scripts/private-material.mjs
- name: The page's own checks
run: node --test 'test/*.test.mjs'

# The same build as the Pages workflow, without the deploy: the docs build against
# uptide-dev/uptide@main and no internal link is broken.
site:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version-file: docs-site/.node-version
cache: npm
cache-dependency-path: docs-site/package-lock.json
- name: Build the docs from uptide-dev/uptide@main
working-directory: docs-site
env:
ASTRO_TELEMETRY_DISABLED: '1'
run: |
npm ci
npm run build
- name: Put the landing page and the docs together
run: node scripts/assemble-site.mjs _site
- name: No broken internal links
run: node scripts/check-links.mjs _site
33 changes: 26 additions & 7 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
name: Pages

# Publishes site/ to GitHub Pages as it is, with no build step: on a push to main that
# changes it, or by hand. See site/README.md.
# Publishes the landing page (site/, as it is) at / and the docs (docs-site/, built with
# Starlight from uptide-dev/uptide's docs/ folder) at /docs. The docs live in the other
# repository, so the site is rebuilt on every push to main here, once a day to pick up docs
# changes there, and by hand. See README.md.
on:
push:
branches: [main]
paths: ['site/**', '.github/workflows/pages.yml']
schedule:
- cron: '23 5 * * *'
workflow_dispatch:

concurrency:
Expand Down Expand Up @@ -33,15 +36,31 @@ jobs:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version-file: docs-site/.node-version
cache: npm
cache-dependency-path: docs-site/package-lock.json
- name: Build the docs from uptide-dev/uptide@main
working-directory: docs-site
env:
ASTRO_TELEMETRY_DISABLED: '1'
run: |
npm ci
npm run build
- name: Put the landing page and the docs together
run: node scripts/assemble-site.mjs _site
- name: Write the site URL into the page
run: |
sed -i "s#%SITE_URL%#${SITE_URL}#g" site/index.html
if grep -q '%SITE_URL%' site/index.html; then
echo "::error::site/index.html still has a %SITE_URL% placeholder."
sed -i "s#%SITE_URL%#${SITE_URL}#g" _site/index.html
if grep -q '%SITE_URL%' _site/index.html; then
echo "::error::_site/index.html still has a %SITE_URL% placeholder."
exit 1
fi
- name: No broken internal links
run: node scripts/check-links.mjs _site
- uses: actions/upload-pages-artifact@v3
with:
path: site
path: _site
- id: deployment
uses: actions/deploy-pages@v4
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_site/
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,38 @@
The landing page of [Uptide](https://github.com/uptide-dev/uptide), published at
https://uptide-dev.github.io.

The page is `site/`: static HTML with inline CSS, self-hosted fonts and no build step. What
each file is, and where every number on the page comes from: [site/README.md](site/README.md).
Two parts, published together:

- **The landing page** at `/` is `site/`: static HTML with inline CSS, self-hosted fonts and
no build step. What each file is, and where every number on the page comes from:
[site/README.md](site/README.md).
- **The docs** at `/docs` are `docs-site/`, built with Astro Starlight from
uptide-dev/uptide's `docs/` folder, checked out at build time and never copied here:
[docs-site/README.md](docs-site/README.md).

## See it locally

```sh
python3 -m http.server 8000 --directory site # then open http://localhost:8000
```

That is the landing page alone. For both, as deployed:

```sh
(cd docs-site && npm ci && npm run build)
node scripts/assemble-site.mjs && node scripts/check-links.mjs
python3 -m http.server 8000 --directory _site # http://localhost:8000 and /docs/
```

`%SITE_URL%` in the page's `<head>` is expected: the deploy writes the real address there
(canonical and social-preview URLs only; nothing visible).

## Publishing

`.github/workflows/pages.yml` deploys `site/` to GitHub Pages on every push to `main` that
changes it. Its `SITE_URL` is the one value to change if the page moves to a domain.
`.github/workflows/pages.yml` builds the docs, puts them under `/docs` next to `site/`, checks
every internal link and deploys to GitHub Pages: on every push to `main`, daily (to pick up
docs changes in uptide-dev/uptide), and by hand. Its `SITE_URL` is the one value to change if
the page moves to a domain; the docs take their canonical and `og:image` URLs from it too.

One-time setup:

Expand All @@ -33,10 +49,14 @@ One-time setup:
- **DCO**: every commit is signed off (`git commit -s`), as in uptide-dev/uptide.
- **No private material**: no private planning document and no identifier from the denylist.
- **The page's own tests** (`node --test 'test/*.test.mjs'`): every font next to its license,
the URLs from `SITE_URL`, nothing loaded from another origin, the deploy's trigger and
permissions.
the URLs from `SITE_URL`, nothing loaded from another origin, the deploy's triggers and
permissions, exact docs dependency versions, no docs committed, and the docs transforms
(titles, sidebar, links).
- **The site build**: the docs build against uptide-dev/uptide@main and
`scripts/check-links.mjs` finds no broken internal link or anchor in landing + docs.

`scripts/` (`dco.mjs`, `bots.mjs`, `public-tree.mjs`, `private-material.mjs`) and
`scripts/assemble-site.mjs` and `scripts/check-links.mjs` belong to this repository. The rest
of `scripts/` (`dco.mjs`, `bots.mjs`, `public-tree.mjs`, `private-material.mjs`) and
`.github/workflows/dco.yml` are copies from uptide-dev/uptide, where they are tested. Change
them there first, then copy them here.

Expand Down
7 changes: 7 additions & 0 deletions docs-site/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
dist/
.astro/
# Built from uptide-dev/uptide on every build by scripts/fetch-docs.mjs; never committed.
.cache/
src/content/docs/
src/generated/
1 change: 1 addition & 0 deletions docs-site/.node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.22.0
2 changes: 2 additions & 0 deletions docs-site/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
save-exact=true
engine-strict=true
63 changes: 63 additions & 0 deletions docs-site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Docs site

The Uptide documentation at `/docs`, built with [Starlight](https://starlight.astro.build)
from [uptide-dev/uptide](https://github.com/uptide-dev/uptide)'s `docs/` folder. The docs
are never copied into this repository: every build checks out `main` of uptide-dev/uptide
(anonymous HTTPS) and generates the content collection from it.

```sh
npm ci
npm run build # fetch the docs, then astro build into dist/
npm run dev # fetch the docs, then a dev server at http://localhost:4321/docs/
```

To see it with the landing page as it is deployed, from the repository root:

```sh
node scripts/assemble-site.mjs # site/ at /, docs-site/dist at /docs → _site/
node scripts/check-links.mjs # no broken internal link or #anchor
python3 -m http.server 8000 --directory _site # http://localhost:8000/docs/
```

`UPTIDE_CHECKOUT=/path/to/uptide` builds from a local checkout instead of cloning (offline
work, or previewing docs changes before they land); `UPTIDE_REF` picks another branch.

## How the content is made

`scripts/fetch-docs.mjs` runs before every build. It clones uptide-dev/uptide into `.cache/`
and writes one page per `docs/**/*.md` (except `docs/screenshots/`) into `src/content/docs/`;
both are gitignored.

- `docs/README.md` is the index page.
- A page's front matter `title` and `description` are used as they are. A page without them
takes its title from its first `# ` heading and its description from its first paragraph.
- The first `# ` heading is dropped, since Starlight renders the title as the page's h1.
- Each page's "Edit page" link opens the file on GitHub.

`src/remark-uptide-links.mjs` rewrites links when a page renders: a link to another page
under `docs/` stays on this site (`../concepts.md#exit-codes` → `/docs/concepts/#exit-codes`),
and a link to anything else in the repository (`../CONTRIBUTING.md`, `fixtures/`, a folder
under `docs/`) goes to its URL on GitHub.

`src/sidebar.mjs` builds the sidebar from the tables in `docs/README.md`: "Using Uptide"
first, then "Contributing and internals", in the order the README lists them. A folder
(`decisions/`) becomes a collapsed group of its pages; a file outside `docs/` links to GitHub.
A README without those two sections fails the build.

## Design

`src/styles/uptide.css` maps the landing page's tokens onto Starlight's: the same background,
surface, line, text, body and accent colors in each theme, Space Grotesk headings, Instrument
Sans body and IBM Plex Mono code (the font files are the landing page's, in `site/fonts/`),
square corners, 1px rules and no shadows. Code blocks are Expressive Code with one dark theme
on `#131210` in both themes. `src/components/SiteTitle.astro` is the landing page's mark and
wordmark, linking to `/`. `public/favicon.svg` is a link to `site/favicon.svg`.

In light mode the dim text color is `#6A675F` rather than the landing page's `#76736B`, which
falls just short of 4.5:1 for small text on the page background.

## Versions

Every dependency is pinned to an exact version (`.npmrc` has `save-exact=true`), with the
lockfile committed, and Node is pinned in `.node-version`. To upgrade, install the exact new
version (`npm i astro@x.y.z`), rebuild, and run the checks above.
68 changes: 68 additions & 0 deletions docs-site/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// The docs site, served at /docs next to the landing page (site/). Content comes from
// uptide-dev/uptide's docs/ folder at build time: see scripts/fetch-docs.mjs.
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import { unified } from '@astrojs/markdown-remark';
import remarkUptideLinks from './src/remark-uptide-links.mjs';
import { sidebar } from './src/sidebar.mjs';

// The site's address, as in .github/workflows/pages.yml; canonical and og:image URLs use it.
const SITE_URL = process.env.SITE_URL || 'https://uptide-dev.github.io/';
const base = '/docs';
const siteDir = fileURLToPath(new URL('.', import.meta.url));
const ogImage = new URL('og.png', SITE_URL).href;

export default defineConfig({
site: SITE_URL,
base,
trailingSlash: 'always',
build: { format: 'directory' },
markdown: { processor: unified({ remarkPlugins: [[remarkUptideLinks, { base }]] }) },
integrations: [
starlight({
title: 'Uptide docs',
description:
'Documentation for Uptide, the open-source CLI that shows what a dependency upgrade breaks in your code and opens a verified migration branch or PR.',
favicon: '/favicon.svg',
social: [
{ icon: 'github', label: 'GitHub', href: 'https://github.com/uptide-dev/uptide' },
{ icon: 'npm', label: 'npm', href: 'https://www.npmjs.com/package/uptide' },
],
sidebar: sidebar(siteDir),
components: { SiteTitle: './src/components/SiteTitle.astro' },
customCss: ['./src/styles/uptide.css'],
head: [
{ tag: 'meta', attrs: { property: 'og:image', content: ogImage } },
{ tag: 'meta', attrs: { property: 'og:image:width', content: '1280' } },
{ tag: 'meta', attrs: { property: 'og:image:height', content: '640' } },
{ tag: 'meta', attrs: { name: 'twitter:card', content: 'summary_large_image' } },
{ tag: 'meta', attrs: { name: 'twitter:image', content: ogImage } },
],
// Code blocks are a dark terminal in both themes, like the landing page's output blocks.
expressiveCode: {
themes: ['github-dark-default'],
useStarlightDarkModeSwitch: false,
useStarlightUiThemeColors: false,
styleOverrides: {
borderRadius: '0',
borderColor: '#2B2925',
codeBackground: '#131210',
codeFontFamily: "'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace",
uiFontFamily: "'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace",
frames: {
shadowColor: 'transparent',
editorBackground: '#131210',
terminalBackground: '#131210',
editorTabBarBackground: '#1B1A17',
editorActiveTabBackground: '#131210',
terminalTitlebarBackground: '#1B1A17',
terminalTitlebarBorderBottomColor: '#2B2925',
editorTabBarBorderBottomColor: '#2B2925',
frameBoxShadowCssValue: 'none',
},
},
},
}),
],
});
Loading
Loading