Skip to content
Closed
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
20 changes: 20 additions & 0 deletions fern/scripts/fern-published-branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
"site",
}
PUBLISH_METADATA_PATH = Path("fern/publish-metadata.json")
FERN_ROOT_CONFIG_PATHS = [
"fern/docs.yml",
"fern/fern.config.json",
]
FERN_DEVNOTE_SUPPORT_PATHS = [
"fern/assets",
"fern/components/Authors.tsx",
Expand Down Expand Up @@ -204,6 +208,12 @@ def copy_path(source: Path, target: Path) -> None:
shutil.copy2(source, target)


def copy_required_path(source: Path, target: Path) -> None:
if not source.exists():
raise PublishedBranchError(f"Missing required source path: {source}")
copy_path(source, target)


def clear_published_tree(root: Path) -> None:
root.mkdir(parents=True, exist_ok=True)
for path in root.iterdir():
Expand Down Expand Up @@ -317,6 +327,14 @@ def materialize_version_nav_pages(published_root: Path) -> None:
nav.write_text("".join(lines))


def sync_fern_root_config(source_root: Path, published_root: Path) -> None:
preserved_versions_block = normalize_latest_display_name(versions_block(published_root / "fern" / "docs.yml"))
for rel_path in FERN_ROOT_CONFIG_PATHS:
copy_required_path(source_root / rel_path, published_root / rel_path)
restore_versions_block(published_root / "fern" / "docs.yml", preserved_versions_block)
validate_redirect_targets(published_root)


def sync_source(args: argparse.Namespace) -> int:
source_root = Path(args.source_root)
published_root = Path(args.published_root)
Expand Down Expand Up @@ -383,6 +401,8 @@ def patch_devnotes(args: argparse.Namespace) -> int:
if not target_nav.exists():
raise PublishedBranchError(f"Missing {target_nav}; publish a Fern release snapshot first")

sync_fern_root_config(source_root, published_root)

for rel_path in FERN_DEVNOTE_SUPPORT_PATHS:
copy_path(source_root / rel_path, published_root / rel_path)

Expand Down
129 changes: 129 additions & 0 deletions packages/data-designer/tests/docs/test_fern_published_branch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

import argparse
import importlib.util
from pathlib import Path
from types import ModuleType

SCRIPT_PATH = Path(__file__).resolve().parents[4] / "fern" / "scripts" / "fern-published-branch.py"


def load_script_module() -> ModuleType:
spec = importlib.util.spec_from_file_location("fern_published_branch", SCRIPT_PATH)
assert spec is not None
loader = spec.loader
assert loader is not None
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
return module


def write_text(path: Path, text: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text)


def patch_args(source_root: Path, published_root: Path) -> argparse.Namespace:
return argparse.Namespace(
source_root=source_root,
published_root=published_root,
metadata_source_repository=None,
metadata_source_ref=None,
metadata_source_sha=None,
metadata_release_tag=None,
metadata_published_branch=None,
)


def test_patch_devnotes_syncs_root_config_and_preserves_published_versions(tmp_path: Path) -> None:
module = load_script_module()
source_root = tmp_path / "source"
published_root = tmp_path / "published"

write_text(
source_root / "fern" / "docs.yml",
"""instances:
- url: datadesigner.docs.buildwithfern.com/nemo/datadesigner
title: Source Fern Docs
global-theme: nvidia
navbar-links:
- type: github
value: https://github.com/NVIDIA-NeMo/DataDesigner
versions:
- display-name: "Latest"
path: versions/latest.yml
slug: latest
redirects:
- source: "/nemo/datadesigner/getting-started"
destination: "/nemo/datadesigner/getting-started/welcome"
""",
)
write_text(source_root / "fern" / "fern.config.json", '{"organization": "nvidia", "version": "5.41.1"}\n')
write_text(source_root / "fern" / "assets" / "current-devnote-asset.png", "new asset")
write_text(
source_root / "fern" / "versions" / "latest.yml",
"""navigation:
- section: Dev Notes
contents:
- page: New Note
path: ./latest/pages/devnotes/posts/new-note.mdx
- section: Concepts
contents: []
""",
)
write_text(source_root / "fern" / "versions" / "latest" / "pages" / "devnotes" / "posts" / "new-note.mdx", "# New")

write_text(
published_root / "fern" / "docs.yml",
"""instances:
- url: datadesigner.docs.buildwithfern.com/nemo/datadesigner
title: Published Fern Docs
footer: ./components/OldFooter.tsx
layout:
searchbar-placement: header
versions:
- display-name: latest
path: versions/latest.yml
slug: latest
- display-name: "v0.6.0"
path: versions/v0.6.0.yml
slug: v0.6.0
redirects:
- source: "/nemo/datadesigner/getting-started"
destination: "/nemo/datadesigner/getting-started/welcome"
""",
)
write_text(published_root / "fern" / "fern.config.json", '{"organization": "nvidia", "version": "4.106.0"}\n')
write_text(published_root / "fern" / "assets" / "published-only-asset.png", "old asset")
write_text(
published_root / "fern" / "versions" / "latest.yml",
"""navigation:
- section: Dev Notes
contents:
- page: Old Note
path: ./latest/pages/devnotes/posts/old-note.mdx
- section: Concepts
contents: []
""",
)

assert module.patch_devnotes(patch_args(source_root, published_root)) == 0

published_docs = (published_root / "fern" / "docs.yml").read_text()
assert "title: Source Fern Docs" in published_docs
assert "global-theme: nvidia" in published_docs
assert "navbar-links:" in published_docs
assert "title: Published Fern Docs" not in published_docs
assert "footer: ./components/OldFooter.tsx" not in published_docs
assert "searchbar-placement: header" not in published_docs
assert '- display-name: "Latest"' in published_docs
assert 'display-name: "v0.6.0"' in published_docs
assert (published_root / "fern" / "fern.config.json").read_text() == (
'{"organization": "nvidia", "version": "5.41.1"}\n'
)
assert (published_root / "fern" / "assets" / "current-devnote-asset.png").read_text() == "new asset"
assert not (published_root / "fern" / "assets" / "published-only-asset.png").exists()
assert (published_root / "fern" / "versions" / "latest" / "pages" / "devnotes" / "posts" / "new-note.mdx").exists()
Loading