parent
b12da23918
commit
cffc6c4b50
|
|
@ -61,7 +61,7 @@ Process:
|
|||
- Preserve the existing changelog style and sections: `Added`, `Changed`, `Fixed`, `Removed`, and `Breaking Changes` when applicable.
|
||||
|
||||
7. Audit next-release public docs.
|
||||
- Treat root `README.md` and the current stable docs source as the latest released public docs. While `docs/versions/manifest.json` has `stable_source: legacy`, that source is `website/src/content/docs/`; afterward it is the current immutable snapshot under `docs/versions/<current>/website/src/content/docs/`.
|
||||
- Treat root `README.md` and the version selected by `docs/versions/manifest.json` under `docs/versions/<current>/website/src/content/docs/` as the latest released public docs. Published version docs may contain factual corrections made after the release tag.
|
||||
- Treat `docs/next/README.md` as the next-release root README and `docs/next/website/src/content/docs/` as the complete unpublished website-doc draft.
|
||||
- Treat `docs/preview/website/` as bot-owned output for the active preview release. Never edit it during release review and never use it as the stable release source.
|
||||
- Compare meaningful user-facing changes in the range against next-release docs first.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
with:
|
||||
bun-version: 1.3.14
|
||||
|
||||
- name: Validate published snapshots
|
||||
- name: Validate published documentation
|
||||
run: |
|
||||
node website/scripts/docs-versions.mjs check
|
||||
node website/scripts/docs-preview.mjs check
|
||||
|
|
|
|||
|
|
@ -163,9 +163,9 @@ Unreleased docs live in `docs/next/website/src/content/docs/`. Update those when
|
|||
|
||||
The active preview release docs live in `docs/preview/website/`. Preview CI owns this mutable snapshot and commits it atomically with `website/preview.json`; never edit it manually. Validate it with `node website/scripts/docs-preview.mjs check`.
|
||||
|
||||
Immutable stable release snapshots live in `docs/versions/`. The website build generates `/docs/preview/` from the active preview snapshot and `/docs/<version>/` from stable snapshots. The current stable `/docs/` temporarily uses the tracked legacy `website/src/content/docs/` tree; the next stable release switches it to the current immutable snapshot and removes the legacy copy. Do not edit generated preview, version, or snapshot-backed stable files under `website/src/content/docs/`.
|
||||
Published stable-release documentation lives in `docs/versions/`. Release CI seeds each version from the tagged `docs/next` tree, and maintainers may correct factual documentation errors in a published version afterward. Apply a correction separately to `docs/next` when it also applies to future releases; never replace a published tree with the current draft. The website build generates `/docs/preview/` from the active preview snapshot, `/docs/<version>/` from the maintained version directories, and `/docs/` from the version selected by `docs/versions/manifest.json`. Do not edit generated files under `website/src/content/docs/`.
|
||||
|
||||
During release review, finalize `docs/next` and run `just release-docs-check`. Do not copy draft docs into preview or stable manually. Preview CI snapshots the selected commit. After a stable GitHub Release succeeds, release CI snapshots the exact tag, updates `latest.json`, and deploys them together. Normal feature/fix work should not edit root `README.md`, root `CHANGELOG.md`, legacy stable website docs, or `website/latest.json` unless explicitly requested.
|
||||
During release review, finalize `docs/next` and run `just release-docs-check`. Do not copy draft docs into preview or published versions manually. Preview CI snapshots the selected commit. After a stable GitHub Release succeeds, release CI seeds a new version from the exact tag, updates `latest.json`, and deploys them together. Normal feature/fix work should not edit root `README.md`, root `CHANGELOG.md`, published version docs, or `website/latest.json` unless it is a focused correction to already-published documentation or explicitly requested.
|
||||
|
||||
Put local PRDs, planning notes, and exploratory specs under `.local/prd/`; `.local/` is ignored and locally controlled.
|
||||
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ If your proposal changes the visual language, interaction model, workflow, persi
|
|||
|
||||
## Documentation for unreleased changes
|
||||
|
||||
The root `README.md`, root `CHANGELOG.md`, and public website docs describe released Herdr builds. Do not update root `README.md`, root `CHANGELOG.md`, `docs/preview/`, `docs/versions/`, or `website/src/content/docs/` for normal PRs.
|
||||
The root `README.md`, root `CHANGELOG.md`, and public website docs describe released Herdr builds. Do not update root `README.md`, root `CHANGELOG.md`, `docs/preview/`, `docs/versions/`, or `website/src/content/docs/` for normal code PRs. A focused correction to already-published documentation may update the affected `docs/versions/<version>/` files and should make the same correction under `docs/next` when it remains relevant to future releases.
|
||||
|
||||
If your PR changes user-facing behavior, mention the needed public-doc update in the PR. Update `docs/next/README.md` only when the root README needs to change for the next stable release. Update the draft under `docs/next/website/src/content/docs/` when website docs need to change. Draft changes stay unpublished until preview CI snapshots a selected commit or stable release CI snapshots a tag; contributors and maintainers do not copy them into public docs manually.
|
||||
If your PR changes user-facing behavior, mention the needed public-doc update in the PR. Update `docs/next/README.md` only when the root README needs to change for the next stable release. Update the draft under `docs/next/website/src/content/docs/` when website docs need to change. Draft changes stay unpublished until preview CI snapshots a selected commit or stable release CI seeds a new version from a tag; contributors and maintainers do not copy an entire draft tree into published docs manually.
|
||||
|
||||
You do not need to edit the changelog for normal PRs. Maintainers prepare `docs/next/CHANGELOG.md` during release review.
|
||||
|
||||
|
|
|
|||
|
|
@ -373,6 +373,8 @@ position = "bottom-right"
|
|||
|
||||
Choose `herdr` for an in-app toast, `terminal` for an outer-terminal notification that works well over SSH, `system` for the local OS notification service, or `off` to disable popups. Herdr suppresses popups for the active tab. Search `ui.toast` in the [Config reference](/docs/config-reference/) for positions, delay behavior, and clipboard feedback settings.
|
||||
|
||||
On macOS, `system` tries `terminal-notifier` first and falls back to `/usr/bin/osascript` when it is unavailable or fails. The fallback appears as Script Editor in Notification Center and cannot activate the hosting terminal. Install `terminal-notifier` with `brew install terminal-notifier`. For a supported, detected terminal, it can activate the terminal app when you click the notification. Alternatively, choose `terminal` to let a supported outer terminal own the notification.
|
||||
|
||||
## Sound
|
||||
|
||||
Sound notifications play through the local Herdr client. Custom sounds must be mp3 files; relative paths are resolved from the config file's directory.
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ position = "bottom-right"
|
|||
|
||||
アプリ内トーストには `herdr`、SSH 越しでも使いやすい外側のターミナル通知には `terminal`、ローカル OS の通知サービスには `system`、ポップアップを無効にするには `off` を選びます。Herdr はアクティブなタブのポップアップを抑制します。位置、遅延の挙動、クリップボードのフィードバック設定については、[設定リファレンス](/docs/config-reference/)で `ui.toast` を検索してください。
|
||||
|
||||
macOS では、`system` は最初に `terminal-notifier` を試し、利用できない場合や失敗した場合は `/usr/bin/osascript` にフォールバックします。このフォールバックは通知センターで Script Editor として表示され、ホストターミナルをアクティブにできません。`brew install terminal-notifier` で `terminal-notifier` をインストールできます。対応するターミナルを Herdr が検出できた場合、通知のクリック時にそのターミナルアプリをアクティブにできます。または、`terminal` を選んで対応する外側のターミナルに通知を送信させてください。
|
||||
|
||||
## サウンド
|
||||
|
||||
サウンド通知はローカルの Herdr クライアントで再生されます。カスタムサウンドは mp3 ファイルでなければなりません。相対パスは設定ファイルのディレクトリから解決されます。
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ position = "bottom-right"
|
|||
|
||||
选择 `herdr` 可使用应用内 toast,选择 `terminal` 可使用适合 SSH 场景的外层终端通知,选择 `system` 可使用本地操作系统通知服务,选择 `off` 可禁用弹出通知。Herdr 会抑制活动标签页的弹出通知。在[配置参考](/docs/config-reference/)中搜索 `ui.toast`,可查看位置、延迟行为和剪贴板反馈设置。
|
||||
|
||||
在 macOS 上,`system` 会先尝试 `terminal-notifier`;如果它不可用或执行失败,则回退到 `/usr/bin/osascript`。该回退方式会在通知中心显示为 Script Editor,并且无法激活承载 Herdr 的终端。可运行 `brew install terminal-notifier` 安装 `terminal-notifier`。如果 Herdr 检测到受支持的终端,点击通知时它可以激活该终端应用。也可以选择 `terminal`,让受支持的外层终端负责发送通知。
|
||||
|
||||
## 声音
|
||||
|
||||
声音通知通过本地 Herdr 客户端播放。自定义声音必须是 mp3 文件;相对路径从配置文件所在目录解析。
|
||||
|
|
|
|||
|
|
@ -373,6 +373,8 @@ position = "bottom-right"
|
|||
|
||||
Choose `herdr` for an in-app toast, `terminal` for an outer-terminal notification that works well over SSH, `system` for the local OS notification service, or `off` to disable popups. Herdr suppresses popups for the active tab. Search `ui.toast` in the [Config reference](/docs/config-reference/) for positions, delay behavior, and clipboard feedback settings.
|
||||
|
||||
On macOS, `system` tries `terminal-notifier` first and falls back to `/usr/bin/osascript` when it is unavailable or fails. The fallback appears as Script Editor in Notification Center and cannot activate the hosting terminal. Install `terminal-notifier` with `brew install terminal-notifier`. For a supported, detected terminal, it can activate the terminal app when you click the notification. Alternatively, choose `terminal` to let a supported outer terminal own the notification.
|
||||
|
||||
## Sound
|
||||
|
||||
Sound notifications play through the local Herdr client. Custom sounds must be mp3 files; relative paths are resolved from the config file's directory.
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ position = "bottom-right"
|
|||
|
||||
アプリ内トーストには `herdr`、SSH 越しでも使いやすい外側のターミナル通知には `terminal`、ローカル OS の通知サービスには `system`、ポップアップを無効にするには `off` を選びます。Herdr はアクティブなタブのポップアップを抑制します。位置、遅延の挙動、クリップボードのフィードバック設定については、[設定リファレンス](/docs/config-reference/)で `ui.toast` を検索してください。
|
||||
|
||||
macOS では、`system` は最初に `terminal-notifier` を試し、利用できない場合や失敗した場合は `/usr/bin/osascript` にフォールバックします。このフォールバックは通知センターで Script Editor として表示され、ホストターミナルをアクティブにできません。`brew install terminal-notifier` で `terminal-notifier` をインストールできます。対応するターミナルを Herdr が検出できた場合、通知のクリック時にそのターミナルアプリをアクティブにできます。または、`terminal` を選んで対応する外側のターミナルに通知を送信させてください。
|
||||
|
||||
## サウンド
|
||||
|
||||
サウンド通知はローカルの Herdr クライアントで再生されます。カスタムサウンドは mp3 ファイルでなければなりません。相対パスは設定ファイルのディレクトリから解決されます。
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ position = "bottom-right"
|
|||
|
||||
选择 `herdr` 可使用应用内 toast,选择 `terminal` 可使用适合 SSH 场景的外层终端通知,选择 `system` 可使用本地操作系统通知服务,选择 `off` 可禁用弹出通知。Herdr 会抑制活动标签页的弹出通知。在[配置参考](/docs/config-reference/)中搜索 `ui.toast`,可查看位置、延迟行为和剪贴板反馈设置。
|
||||
|
||||
在 macOS 上,`system` 会先尝试 `terminal-notifier`;如果它不可用或执行失败,则回退到 `/usr/bin/osascript`。该回退方式会在通知中心显示为 Script Editor,并且无法激活承载 Herdr 的终端。可运行 `brew install terminal-notifier` 安装 `terminal-notifier`。如果 Herdr 检测到受支持的终端,点击通知时它可以激活该终端应用。也可以选择 `terminal`,让受支持的外层终端负责发送通知。
|
||||
|
||||
## 声音
|
||||
|
||||
声音通知通过本地 Herdr 客户端播放。自定义声音必须是 mp3 文件;相对路径从配置文件所在目录解析。
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
# Versioned documentation
|
||||
|
||||
This directory contains immutable documentation snapshots for stable Herdr releases.
|
||||
This directory contains the published documentation for stable Herdr releases.
|
||||
|
||||
Do not edit snapshot files manually. They must match the release tag recorded in `manifest.json`. Validate them with:
|
||||
Release CI creates each version from the tagged `docs/next` tree after the GitHub Release succeeds. Maintainers can correct published documentation in its version directory afterward. When a correction also applies to future releases, make the same focused change under `docs/next`; do not replace a published tree with the current draft.
|
||||
|
||||
Validate the manifest and build every published version with:
|
||||
|
||||
```bash
|
||||
node website/scripts/docs-versions.mjs check
|
||||
cd website && bun run build
|
||||
```
|
||||
|
||||
Release CI creates a new snapshot from the tagged `docs/next` tree after the GitHub Release succeeds. `website/scripts/prepare-docs.mjs` renders these snapshots at `/docs/<version>/` and uses the current snapshot for `/docs/` after the legacy stable-doc migration completes. `/docs/preview/` comes only from the active preview release snapshot in `docs/preview/`, never directly from `docs/next/`.
|
||||
`website/scripts/prepare-docs.mjs` renders each maintained version at `/docs/<version>/` and uses the version selected by `manifest.json` for `/docs/`. Generated files under `website/src/content/docs/` are not editable sources. `/docs/preview/` comes only from the active preview release snapshot in `docs/preview/`, never directly from `docs/next/`.
|
||||
|
||||
The `tag`, `commit`, and `source` fields in `manifest.json` record where release CI initially published a version. Git history records later documentation corrections.
|
||||
|
||||
The historical backfill starts at v0.5.11, the first release that included the Astro/Starlight documentation site.
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ file: ../../../public/assets/logo.svg
|
|||
self.assertIn("[Install](/docs/0.7.4/install/)", output)
|
||||
self.assertIn("file: ../../../../../public/assets/logo.svg", output)
|
||||
self.assertIn("from '../../../../components/ConfigReference.astro'", output)
|
||||
self.assertIn("blob/v0.7.4/docs/next/website/src/content/docs/index.mdx", output)
|
||||
self.assertIn("blob/master/docs/versions/0.7.4/website/src/content/docs/index.mdx", output)
|
||||
self.assertIn("blob/v0.7.4/SKILL.md", output)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ Documentation has three lifecycle states:
|
|||
|
||||
- `../docs/next/website/` is the committed, author-edited draft. Production builds never read it.
|
||||
- `../docs/preview/website/` is the latest preview release snapshot, rendered at `/docs/preview/`.
|
||||
- `../docs/versions/<version>/website/` contains immutable stable release snapshots, rendered at `/docs/<version>/`.
|
||||
- `../docs/versions/<version>/website/` contains maintained stable-release documentation, rendered at `/docs/<version>/`. Release CI seeds a new version from its tag; later factual corrections are made directly in that version directory and mirrored to `docs/next` when they also apply to future releases.
|
||||
|
||||
The current stable site temporarily remains tracked under `src/content/docs/` because it contains post-v0.7.5 documentation corrections. The next stable release switches `docs/versions/manifest.json` to snapshot-backed stable docs and removes that legacy copy. From then on, `src/content/docs/` is entirely generated and ignored.
|
||||
The version selected by `docs/versions/manifest.json` is also rendered at `/docs/`. `src/content/docs/` is entirely generated and ignored.
|
||||
|
||||
Preview CI snapshots the selected commit and updates `preview.json` in one commit:
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ node website/scripts/docs-preview.mjs snapshot <commit>
|
|||
node website/scripts/docs-preview.mjs check
|
||||
```
|
||||
|
||||
Stable release CI snapshots the exact tag after the GitHub Release succeeds:
|
||||
Stable release CI seeds a new maintained version from the exact tag after the GitHub Release succeeds:
|
||||
|
||||
```bash
|
||||
node website/scripts/docs-versions.mjs publish <tag>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ assertIncludes(preview, 'name="robots" content="noindex, nofollow"');
|
|||
assertIncludes(archived, `data-pagefind-filter="version[content]" content="${versions.current}"`);
|
||||
assertIncludes(archived, 'name="robots" content="noindex, nofollow"');
|
||||
if (archived.includes(`This page documents Herdr ${versions.current}`)) {
|
||||
throw new Error('the current immutable snapshot must not be labeled as outdated');
|
||||
throw new Error('the current documentation version must not be labeled as outdated');
|
||||
}
|
||||
const versionSelect = stable.match(/<select[^>]*aria-label="Documentation version"[^>]*>([\s\S]*?)<\/select>/)?.[1];
|
||||
if (!versionSelect) throw new Error('stable docs are missing the version selector');
|
||||
|
|
@ -68,7 +68,7 @@ if (previous) {
|
|||
const sitemap = await readFile(resolve(distDir, 'sitemap-0.xml'), 'utf8');
|
||||
assertIncludes(sitemap, 'https://herdr.dev/docs/');
|
||||
if (nonCanonicalDocsUrl.test(sitemap)) {
|
||||
throw new Error('preview or immutable documentation URLs must not appear in the sitemap');
|
||||
throw new Error('preview or versioned documentation URLs must not appear in the sitemap');
|
||||
}
|
||||
|
||||
const build = await inspectFiles(distDir);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export async function compareGitTree(git, ref, sourceRoot, snapshotRoot) {
|
|||
assertRelativePath(relativePath, entry.path);
|
||||
expected.set(relativePath, entry);
|
||||
}
|
||||
const actualPaths = await listSnapshotPaths(snapshotRoot);
|
||||
const actualPaths = await listDocumentationPaths(snapshotRoot);
|
||||
const expectedPaths = [...expected.keys()].sort();
|
||||
if (JSON.stringify(actualPaths) !== JSON.stringify(expectedPaths)) {
|
||||
throw new Error(`${snapshotRoot} file list differs from ${ref}:${sourceRoot}`);
|
||||
|
|
@ -89,7 +89,7 @@ export async function compareGitTree(git, ref, sourceRoot, snapshotRoot) {
|
|||
}
|
||||
}
|
||||
|
||||
async function listSnapshotPaths(root) {
|
||||
export async function listDocumentationPaths(root) {
|
||||
const paths = [];
|
||||
async function walk(directory) {
|
||||
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { afterEach, describe, expect, test } from 'bun:test';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
||||
import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
|
||||
|
|
@ -21,7 +21,8 @@ describe('documentation release publishing', () => {
|
|||
await write(root, 'website/latest.json', '{"version":"0.9.0"}\n');
|
||||
await write(root, 'README.md', 'stable readme\n');
|
||||
await write(root, 'README.zh-CN.md', 'stable readme zh-cn\n');
|
||||
await write(root, 'docs/next/website/src/content/docs/index.mdx', 'next docs\n');
|
||||
const nextDocs = '---\ntitle: Documentation\n---\n\nnext docs\n';
|
||||
await write(root, 'docs/next/website/src/content/docs/index.mdx', nextDocs);
|
||||
await write(root, 'docs/next/website/src/data/config-reference.json', '{"next":true}\n');
|
||||
await write(root, 'docs/next/README.md', 'next readme\n');
|
||||
await write(root, 'docs/next/README.zh-CN.md', 'next readme zh-cn\n');
|
||||
|
|
@ -40,7 +41,7 @@ describe('documentation release publishing', () => {
|
|||
await expect(read(root, 'website/src/data/config-reference.json')).rejects.toThrow();
|
||||
expect(await read(root, 'README.md')).toBe('next readme\n');
|
||||
expect(await read(root, 'README.zh-CN.md')).toBe('next readme zh-cn\n');
|
||||
expect(await read(root, 'docs/versions/1.0.0/website/src/content/docs/index.mdx')).toBe('next docs\n');
|
||||
expect(await read(root, 'docs/versions/1.0.0/website/src/content/docs/index.mdx')).toBe(nextDocs);
|
||||
|
||||
const manifest = JSON.parse(await read(root, 'docs/versions/manifest.json'));
|
||||
expect(manifest.current).toBe('1.0.0');
|
||||
|
|
@ -65,7 +66,19 @@ describe('documentation release publishing', () => {
|
|||
`${JSON.stringify({ build_id: 'preview-test', commit: previewCommit })}\n`,
|
||||
);
|
||||
runPrepare(root);
|
||||
expect(await read(root, 'website/src/content/docs/index.mdx')).toBe('next docs\n');
|
||||
const stableDocs = await read(root, 'website/src/content/docs/index.mdx');
|
||||
expect(stableDocs).toContain('next docs');
|
||||
expect(stableDocs).toContain(
|
||||
'editUrl: https://github.com/herdrdev/herdr/blob/master/docs/versions/1.0.0/website/src/content/docs/index.mdx',
|
||||
);
|
||||
const versionedDocs = await read(
|
||||
root,
|
||||
'website/src/content/docs/_versions/1.0.0/index.mdx',
|
||||
);
|
||||
expect(versionedDocs).toContain('next docs');
|
||||
expect(versionedDocs).toContain(
|
||||
'editUrl: https://github.com/herdrdev/herdr/blob/master/docs/versions/1.0.0/website/src/content/docs/index.mdx',
|
||||
);
|
||||
expect(await read(root, 'website/src/content/docs/preview/index.mdx')).toContain(
|
||||
'Preview build `preview-test`',
|
||||
);
|
||||
|
|
@ -74,10 +87,36 @@ describe('documentation release publishing', () => {
|
|||
await write(root, 'website/latest.json', '{"version":"1.0.0"}\n');
|
||||
runScript(root, ['check']);
|
||||
|
||||
const correctedDocs = '---\ntitle: Documentation\n---\n\ncorrected docs\n';
|
||||
await write(
|
||||
root,
|
||||
'docs/versions/1.0.0/website/src/content/docs/index.mdx',
|
||||
correctedDocs,
|
||||
);
|
||||
await write(
|
||||
root,
|
||||
'docs/versions/1.0.0/website/src/data/config-reference.json',
|
||||
'{"corrected":true}\n',
|
||||
);
|
||||
runScript(root, ['check']);
|
||||
|
||||
await write(root, 'README.md', 'post-release correction\n');
|
||||
runScript(root, ['publish', 'v1.0.0']);
|
||||
expect(await read(root, 'README.md')).toBe('post-release correction\n');
|
||||
|
||||
runPrepare(root);
|
||||
expect(await read(root, 'website/src/content/docs/index.mdx')).toContain('corrected docs');
|
||||
expect(await read(root, 'website/src/content/docs/_versions/1.0.0/index.mdx')).toContain(
|
||||
'corrected docs',
|
||||
);
|
||||
expect(await read(root, 'website/src/data/config-reference.json')).toBe(
|
||||
'{"corrected":true}\n',
|
||||
);
|
||||
const versionReferences = JSON.parse(
|
||||
await read(root, 'website/src/data/config-reference-versions.json'),
|
||||
);
|
||||
expect(versionReferences['1.0.0']).toEqual({ corrected: true });
|
||||
|
||||
runScript(root, ['publish', 'v0.9.0']);
|
||||
const archivedManifest = JSON.parse(await read(root, 'docs/versions/manifest.json'));
|
||||
expect(archivedManifest.current).toBe('1.0.0');
|
||||
|
|
@ -85,6 +124,34 @@ describe('documentation release publishing', () => {
|
|||
expect(await read(root, 'README.md')).toBe('post-release correction\n');
|
||||
runScript(root, ['check']);
|
||||
|
||||
const correctedArchivedDocs = '---\ntitle: Documentation\n---\n\ncorrected archived docs\n';
|
||||
await write(
|
||||
root,
|
||||
'docs/versions/0.9.0/website/src/content/docs/index.mdx',
|
||||
correctedArchivedDocs,
|
||||
);
|
||||
runScript(root, ['publish', 'v0.9.0']);
|
||||
expect(await read(root, 'docs/versions/0.9.0/website/src/content/docs/index.mdx')).toBe(
|
||||
correctedArchivedDocs,
|
||||
);
|
||||
|
||||
const archivedDocsRoot = resolve(
|
||||
root,
|
||||
'docs/versions/0.9.0/website/src/content/docs',
|
||||
);
|
||||
await rm(archivedDocsRoot, { recursive: true, force: true });
|
||||
expect(() => runScript(root, ['check'])).toThrow();
|
||||
await write(
|
||||
root,
|
||||
'docs/versions/0.9.0/website/src/content/docs/index.mdx',
|
||||
correctedArchivedDocs,
|
||||
);
|
||||
const linkedPage = resolve(archivedDocsRoot, 'linked.mdx');
|
||||
await symlink('index.mdx', linkedPage);
|
||||
expect(() => runScript(root, ['check'])).toThrow();
|
||||
await rm(linkedPage);
|
||||
runScript(root, ['check']);
|
||||
|
||||
delete archivedManifest.versions[0].commit;
|
||||
await write(root, 'docs/versions/manifest.json', `${JSON.stringify(archivedManifest)}\n`);
|
||||
expect(() => runScript(root, ['check'])).toThrow();
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import {
|
||||
compareGitTree,
|
||||
createGit,
|
||||
extractGitTree,
|
||||
gitPathExists,
|
||||
gitTreesEqual,
|
||||
listDocumentationPaths,
|
||||
resolveCommit,
|
||||
} from './docs-snapshot.mjs';
|
||||
|
||||
|
|
@ -167,38 +167,26 @@ export async function checkVersions() {
|
|||
if (!['website/src/content/docs', 'docs/next/website/src/content/docs'].includes(entry.source)) {
|
||||
throw new Error(`docs version ${entry.version} has unsupported source ${entry.source}`);
|
||||
}
|
||||
const sourceRoot = entry.source;
|
||||
const snapshotRoot = resolve(versionsDir, entry.version, 'website/src/content/docs');
|
||||
await compareGitTree(git, entry.tag, sourceRoot, snapshotRoot);
|
||||
|
||||
const referenceSource = sourceRoot.includes('docs/next/')
|
||||
? 'docs/next/website/src/data/config-reference.json'
|
||||
: 'website/src/data/config-reference.json';
|
||||
const referenceSnapshot = resolve(
|
||||
versionsDir,
|
||||
entry.version,
|
||||
'website/src/data/config-reference.json',
|
||||
const versionRoot = resolve(versionsDir, entry.version, 'website');
|
||||
const documentationPaths = await listDocumentationPaths(
|
||||
resolve(versionRoot, 'src/content/docs'),
|
||||
);
|
||||
if (gitPathExists(git, entry.tag, referenceSource)) {
|
||||
const actualReference = await readFile(referenceSnapshot);
|
||||
const taggedReference = git(['show', `${entry.tag}:${referenceSource}`], { binary: true });
|
||||
if (!actualReference.equals(taggedReference)) {
|
||||
throw new Error(`${entry.version} config reference differs from ${entry.tag}:${referenceSource}`);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await readFile(referenceSnapshot);
|
||||
throw new Error(`${entry.version} has an unexpected config reference snapshot`);
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
}
|
||||
if (!documentationPaths.includes('index.md') && !documentationPaths.includes('index.mdx')) {
|
||||
throw new Error(`docs version ${entry.version} has no root index`);
|
||||
}
|
||||
|
||||
try {
|
||||
JSON.parse(await readFile(resolve(versionRoot, 'src/data/config-reference.json'), 'utf8'));
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!seen.has(manifest.current)) {
|
||||
throw new Error(`current docs version ${manifest.current} has no snapshot`);
|
||||
}
|
||||
process.stdout.write(`validated ${manifest.versions.length} documentation snapshots\n`);
|
||||
process.stdout.write(`validated ${manifest.versions.length} documentation versions\n`);
|
||||
}
|
||||
|
||||
export async function publishVersion(tag) {
|
||||
|
|
@ -217,8 +205,7 @@ export async function publishVersion(tag) {
|
|||
if (!existing?.commit || existing.commit !== release.commit) {
|
||||
throw new Error(`published documentation ${release.version} has mismatched commit provenance`);
|
||||
}
|
||||
await compareGitTree(git, release.commit, existing.source, resolve(versionsDir, release.version, 'website/src/content/docs'));
|
||||
process.stdout.write(`documentation snapshot ${release.tag} is already published\n`);
|
||||
process.stdout.write(`documentation ${release.tag} is already published\n`);
|
||||
return;
|
||||
}
|
||||
if (manifest.current && compareVersions(release.version, manifest.current) < 0) {
|
||||
|
|
@ -229,13 +216,7 @@ export async function publishVersion(tag) {
|
|||
if (existing.commit && existing.commit !== release.commit) {
|
||||
throw new Error(`version ${release.version} has mismatched commit provenance`);
|
||||
}
|
||||
await compareGitTree(
|
||||
git,
|
||||
release.commit,
|
||||
existing.source,
|
||||
resolve(versionsDir, release.version, 'website/src/content/docs'),
|
||||
);
|
||||
process.stdout.write(`documentation snapshot ${release.tag} is already archived\n`);
|
||||
process.stdout.write(`documentation ${release.tag} is already archived\n`);
|
||||
return;
|
||||
}
|
||||
const archived = await snapshotTag(tag, 'docs/next/website/src/content/docs');
|
||||
|
|
@ -251,7 +232,7 @@ export async function publishVersion(tag) {
|
|||
return;
|
||||
}
|
||||
if (existing) {
|
||||
throw new Error(`version ${release.version} already has a documentation snapshot`);
|
||||
throw new Error(`version ${release.version} already has published documentation`);
|
||||
}
|
||||
|
||||
const metadata = await snapshotTag(tag, 'docs/next/website/src/content/docs');
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ if (process.argv[2] === '--rewrite-preview-doc-fixture') {
|
|||
rewriteVersionDocContent(Buffer.concat(chunks).toString('utf8'), {
|
||||
version: process.argv[3] ?? '0.7.5',
|
||||
tag: `v${process.argv[3] ?? '0.7.5'}`,
|
||||
sourceRoot: 'docs/next/website/src/content/docs',
|
||||
relativePath: 'index.mdx',
|
||||
}),
|
||||
);
|
||||
|
|
@ -118,8 +117,8 @@ async function prepareDocs({ draft }) {
|
|||
stableDocsDir,
|
||||
(content, relativePath) =>
|
||||
rewriteStableDocContent(content, {
|
||||
version: currentEntry.version,
|
||||
tag: currentEntry.tag,
|
||||
sourceRoot: currentEntry.source,
|
||||
relativePath,
|
||||
}),
|
||||
);
|
||||
|
|
@ -162,7 +161,6 @@ async function prepareDocs({ draft }) {
|
|||
rewriteVersionDocContent(content, {
|
||||
version,
|
||||
tag: entry.tag,
|
||||
sourceRoot: entry.source,
|
||||
relativePath,
|
||||
}),
|
||||
);
|
||||
|
|
@ -269,24 +267,22 @@ export function rewritePreviewDocContent(
|
|||
return insertPreviewNotice(withSourceLink, relativePath, { buildId, commit });
|
||||
}
|
||||
|
||||
export function rewriteStableDocContent(content, { tag, sourceRoot, relativePath }) {
|
||||
export function rewriteStableDocContent(content, { version, tag, relativePath }) {
|
||||
const taggedContent = rewriteRepositoryLinks(content, tag);
|
||||
return setGeneratedEditUrl(
|
||||
taggedContent,
|
||||
`https://github.com/herdrdev/herdr/blob/${tag}/${sourceRoot}/${relativePath}`,
|
||||
);
|
||||
return setGeneratedEditUrl(taggedContent, versionedDocSourceUrl(version, relativePath));
|
||||
}
|
||||
|
||||
export function rewriteVersionDocContent(content, { version, tag, sourceRoot, relativePath }) {
|
||||
export function rewriteVersionDocContent(content, { version, tag, relativePath }) {
|
||||
const taggedContent = rewriteRepositoryLinks(
|
||||
content.replaceAll('/docs/', `/docs/${version}/`),
|
||||
tag,
|
||||
);
|
||||
const rewritten = rewriteRelativeDocPaths(taggedContent, 2);
|
||||
return setGeneratedEditUrl(
|
||||
rewritten,
|
||||
`https://github.com/herdrdev/herdr/blob/${tag}/${sourceRoot}/${relativePath}`,
|
||||
);
|
||||
return setGeneratedEditUrl(rewritten, versionedDocSourceUrl(version, relativePath));
|
||||
}
|
||||
|
||||
function versionedDocSourceUrl(version, relativePath) {
|
||||
return `https://github.com/herdrdev/herdr/blob/master/docs/versions/${version}/website/src/content/docs/${relativePath}`;
|
||||
}
|
||||
|
||||
function rewriteRepositoryLinks(content, ref) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue