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
3 changes: 2 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
- [ ] `assert_valid_plugin(plugin)` passes
- [ ] Unit tests included and passing (`make test-plugin PLUGIN=<name>`)
- [ ] Plugin installs standalone (`uv pip install -e plugins/<plugin-dir>`)
- [ ] `docs/catalog.md` regenerated if plugin list or metadata changed (`make catalog`)
- [ ] Plugin docs regenerated if plugin docs, list, or metadata changed (`make plugin-docs`)
- [ ] Documentation builds if docs changed (`make docs`)
- [ ] `.github/CODEOWNERS` regenerated if ownership changed (`make codeowners`)
- [ ] Per-plugin `CODEOWNERS` file included (auto-created by `ddp new`)
- [ ] NVIDIA SPDX headers on all files (`make check-license-headers`)
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
with:
name: generated-metadata
path: |
docs/catalog.md.new
docs/plugins/**
zensical.toml
.github/CODEOWNERS.new
if-no-files-found: ignore
68 changes: 68 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Documentation

on:
push:
branches: [main]
pull_request:
paths:
- ".github/workflows/docs.yml"
- "Makefile"
- "devtools/ddp/src/ddp/plugin_docs.py"
- "docs/**"
- "plugins/**/docs/**"
- "pyproject.toml"
- "uv.lock"
- "zensical.toml"
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/configure-pages@v5
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

- uses: astral-sh/setup-uv@v4
with:
python-version: "3.10"
enable-cache: true

- run: make sync
- run: make docs

- uses: actions/upload-pages-artifact@v4
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
path: site

- uses: actions/upload-artifact@v4
if: github.event_name == 'pull_request'
with:
name: docs-site
path: site
if-no-files-found: error

deploy:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/deploy-pages@v4
id: deployment
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Thumbs.db
.coverage
htmlcov/
.mypy_cache/
site/

# Distribution
*.tar.gz
32 changes: 20 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

.PHONY: sync lint format test validate catalog codeowners check-catalog check-codeowners check-license-headers update-license-headers check all bump release build-plugin validate-release test-plugin check-owner
.PHONY: sync lint format test validate docs docs-server plugin-docs check-plugin-docs codeowners check-codeowners check-license-headers update-license-headers check all bump release build-plugin validate-release test-plugin check-owner

# ── Setup ────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -32,7 +32,7 @@ test:
continue; \
fi; \
echo "── Testing $$plugin_name (isolated) ──"; \
uv venv ".venv-$$plugin_name"; \
uv venv --clear ".venv-$$plugin_name"; \
. ".venv-$$plugin_name/bin/activate"; \
uv pip install -e "$$plugin_dir"; \
uv pip install pytest; \
Expand All @@ -47,18 +47,26 @@ test:
validate:
uv run ddp validate

# ── Catalog & CODEOWNERS ─────────────────────────────────────────────────
# ── Documentation ───────────────────────────────────────────────────────

catalog:
uv run ddp catalog > docs/catalog.md
docs: plugin-docs
uv run zensical build --clean --strict

DOCS_DEV_ADDR ?= localhost:8000

docs-server: plugin-docs
uv run zensical serve --dev-addr $(DOCS_DEV_ADDR)

# ── Plugin docs & CODEOWNERS ──────────────────────────────────────────────

plugin-docs:
uv run ddp plugin-docs

codeowners:
uv run ddp codeowners > .github/CODEOWNERS

check-catalog:
uv run ddp catalog > docs/catalog.md.new
diff docs/catalog.md docs/catalog.md.new
@rm -f docs/catalog.md.new
check-plugin-docs:
uv run ddp plugin-docs --check

check-codeowners:
uv run ddp codeowners > .github/CODEOWNERS.new
Expand All @@ -73,9 +81,9 @@ update-license-headers:

# ── Aggregate targets ────────────────────────────────────────────────────

check: check-catalog check-codeowners check-license-headers
check: check-plugin-docs check-codeowners check-license-headers

all: lint test validate check
all: lint test validate check docs

# ── Release ─────────────────────────────────────────────────────────────
# Usage: make release PLUGIN=data-designer-template
Expand All @@ -96,7 +104,7 @@ validate-release:

test-plugin:
@if [ -z "$(PLUGIN)" ]; then echo "ERROR: Set PLUGIN=<name>"; exit 1; fi
uv venv ".venv-$(PLUGIN)"
uv venv --clear ".venv-$(PLUGIN)"
. ".venv-$(PLUGIN)/bin/activate" && \
uv pip install -e "$(PLUGIN_DIR)" && \
uv pip install pytest && \
Expand Down
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 🔌 🎨 NeMo Data Designer Plugins
# NeMo Data Designer Plugins

First-class NVIDIA-provided plugins for [NeMo Data Designer](https://github.com/NVIDIA-NeMo/DataDesigner).

Expand All @@ -16,20 +16,20 @@ Create a new plugin:
uv run ddp new my-plugin
```

This generates a complete plugin skeleton under `plugins/data-designer-my-plugin/` with config, implementation, entry point, tests, and CODEOWNERS. See [docs/adding-a-plugin.md](docs/adding-a-plugin.md) for the full authoring guide.
This generates a complete plugin skeleton under `plugins/data-designer-my-plugin/` with config, implementation, entry point, docs, tests, and CODEOWNERS. See [docs/authoring.md](docs/authoring.md) for the full authoring guide.

## Repository Structure

```
DataDesignerPlugins/
├── devtools/
└── ddp/ # Monorepo management tooling (ddp CLI, dev-only)
├── plugins/ # One directory per plugin (auto-discovered by uv)
└── data-designer-template/ # Reference implementation
└── docs/ # Authoring guide, plugin catalog
|-- devtools/
| `-- ddp/ # Monorepo management tooling (ddp CLI, dev-only)
|-- plugins/ # One directory per plugin (auto-discovered by uv)
| `-- data-designer-template/ # Reference implementation
`-- docs/ # Zensical documentation source
```

Each plugin is an independent Python package with its own `pyproject.toml`, tests, and CODEOWNERS. The root workspace auto-discovers plugins via `plugins/*`.
Each plugin is an independent Python package with its own `pyproject.toml`, docs, tests, and CODEOWNERS. The root workspace auto-discovers plugins via `plugins/*`.

## Development

Expand All @@ -41,8 +41,11 @@ make lint # Lint and format check (ruff)
make format # Auto-fix lint issues and reformat
make test # Test each plugin in an isolated venv
make validate # Run assert_valid_plugin on all entry points
make check # Verify catalog, CODEOWNERS, and license headers are up to date
make all # lint + test + validate + check (full local CI)
make check # Verify generated plugin docs, CODEOWNERS, and license headers are up to date
make plugin-docs # Regenerate docs/plugins/ from per-plugin docs and metadata
make docs # Build the Zensical documentation site
make docs-server # Serve docs locally at http://localhost:8000
make all # lint + test + validate + check + docs (full local CI)
```

To test a single plugin in isolation:
Expand All @@ -51,10 +54,10 @@ To test a single plugin in isolation:
make test-plugin PLUGIN=data-designer-my-plugin
```

If you change plugin metadata or ownership, regenerate derived files:
If you change plugin docs, plugin metadata, or ownership, regenerate derived files:

```bash
make catalog # Regenerate docs/catalog.md
make plugin-docs # Regenerate plugin documentation site inputs
make codeowners # Regenerate CODEOWNERS
make update-license-headers # Fix SPDX headers
```
Expand All @@ -67,7 +70,7 @@ The `ddp` command manages the monorepo. Run `uv run ddp --help` to see all subco
|---------|-------------|
| `ddp new <name>` | Scaffold a new plugin |
| `ddp validate` | Validate all installed plugins |
| `ddp catalog` | Generate plugin catalog to stdout |
| `ddp plugin-docs` | Generate plugin docs site inputs |
| `ddp codeowners` | Aggregate CODEOWNERS to stdout |
| `ddp license-headers` | Add or check SPDX license headers |
| `ddp bump <plugin> <part>` | Bump a plugin's semantic version |
Expand All @@ -83,7 +86,7 @@ make release PLUGIN=data-designer-my-plugin # Tag + build
git push origin data-designer-my-plugin/v0.1.1 # Triggers CI publish
```

See [docs/adding-a-plugin.md](docs/adding-a-plugin.md) for the full release guide.
See [docs/releasing.md](docs/releasing.md) for the full release guide.

## License

Expand Down
2 changes: 1 addition & 1 deletion devtools/ddp/src/ddp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"""Local dev-only monorepo management tooling for data-designer-plugins.

This package is NOT a runtime dependency of any plugin. It provides CLI
tools for scaffolding, validation, catalog generation, CODEOWNERS
tools for scaffolding, validation, plugin docs generation, CODEOWNERS
aggregation, and license-header management across the monorepo.
"""
52 changes: 0 additions & 52 deletions devtools/ddp/src/ddp/catalog.py

This file was deleted.

29 changes: 17 additions & 12 deletions devtools/ddp/src/ddp/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

ddp --help # List all subcommands
ddp new my-plugin # Scaffold a new plugin
ddp plugin-docs # Generate plugin documentation pages
ddp validate # Validate all installed plugins
ddp bump <plugin> patch # Bump a plugin version
"""
Expand Down Expand Up @@ -42,17 +43,21 @@ def build_parser() -> argparse.ArgumentParser:
p_new.add_argument("name", help="Plugin name in kebab-case (e.g., my-cool-thing)")
p_new.set_defaults(func=_run_new)

# ddp catalog
p_catalog = sub.add_parser(
"catalog",
help="Generate plugin catalog to stdout",
# ddp plugin-docs
p_plugin_docs = sub.add_parser(
"plugin-docs",
help="Generate plugin documentation pages",
description=(
"Generate a markdown table of all plugins and their metadata "
"(name, version, column type, description) to stdout. "
"Typically redirected to docs/catalog.md."
"Generate docs/plugins/ from each plugin's docs/ directory and "
"package metadata, then update the generated plugin navigation in zensical.toml."
),
)
p_catalog.set_defaults(func=_run_catalog)
p_plugin_docs.add_argument(
"--check",
action="store_true",
help="Check generated plugin docs without modifying files",
)
p_plugin_docs.set_defaults(func=_run_plugin_docs)

# ddp codeowners
p_codeowners = sub.add_parser(
Expand Down Expand Up @@ -136,11 +141,11 @@ def _run_new(args: argparse.Namespace) -> int:
return 0


def _run_catalog(args: argparse.Namespace) -> int:
from ddp.catalog import main as catalog_main
def _run_plugin_docs(args: argparse.Namespace) -> int:
from ddp.plugin_docs import main as plugin_docs_main

catalog_main()
return 0
argv = ["--check"] if args.check else []
return plugin_docs_main(argv)


def _run_codeowners(args: argparse.Namespace) -> int:
Expand Down
Loading
Loading