Skip to content

Commit e75f004

Browse files
authored
Merge pull request #153 from posit-dev/feat-build-from-repo
feat: build site from repo
2 parents c51867c + fe52cea commit e75f004

4 files changed

Lines changed: 942 additions & 24 deletions

File tree

great_docs/cli.py

Lines changed: 116 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,47 @@ def init(project_path: str | None, force: bool) -> None:
210210
is_flag=True,
211211
help="Build only the latest version (skip historical versions)",
212212
)
213+
@click.option(
214+
"--from-repo",
215+
"from_repo",
216+
type=str,
217+
default=None,
218+
help="Clone a remote Git repository and build its docs (HTTPS or SSH URL)",
219+
)
220+
@click.option(
221+
"--branch",
222+
type=str,
223+
default=None,
224+
help="Branch or tag to check out when using --from-repo (default: repo default)",
225+
)
226+
@click.option(
227+
"--output-dir",
228+
type=click.Path(file_okay=False, dir_okay=True),
229+
default=None,
230+
help="Where to copy the built site when using --from-repo (default: ./great-docs/_site)",
231+
)
232+
@click.option(
233+
"--shallow",
234+
is_flag=True,
235+
help="Force shallow clone with --from-repo (fastest, but no versioned docs or page dates)",
236+
)
237+
@click.option(
238+
"--preview",
239+
"preview_after",
240+
is_flag=True,
241+
help="Start a preview server after building with --from-repo",
242+
)
213243
def build(
214244
project_path: str | None,
215245
watch: bool,
216246
no_refresh: bool,
217247
version_filter: str | None,
218248
latest_only: bool,
249+
from_repo: str | None,
250+
branch: str | None,
251+
output_dir: str | None,
252+
shallow: bool,
253+
preview_after: bool,
219254
) -> None:
220255
"""Build your documentation site.
221256
@@ -226,23 +261,23 @@ def build(
226261
and builds the documentation site. The build directory is ephemeral and
227262
should not be committed to version control.
228263
229-
\b
230-
1. Creates great-docs/ directory with all assets
231-
2. Copies user guide files from project root
232-
3. Generates index.qmd from README.md
233-
4. Refreshes API reference configuration (discovers API changes)
234-
5. Generates llms.txt and llms-full.txt for AI/LLM indexing
235-
6. Creates source links to GitHub
236-
7. Generates CLI reference pages (if enabled)
237-
8. Generates API reference pages
238-
9. Runs Quarto to render the final HTML site in great-docs/_site/
264+
Use --project-path to point to a project in a different directory.
265+
Use --watch to automatically rebuild when source files change.
239266
240267
Use --no-refresh to skip API discovery for faster rebuilds when your
241268
package's public API hasn't changed.
242269
243270
When multi-version documentation is configured, use --versions to build
244271
only specific versions, or --latest-only to skip historical versions.
245272
273+
Use --from-repo to build documentation from a remote Git repository.
274+
This clones the repo into a temporary directory, creates an isolated
275+
virtual environment, installs the package and great-docs, builds the
276+
site, and copies the output to --output-dir (or ./great-docs/_site).
277+
278+
Add --preview to automatically start a local server after a --from-repo
279+
build completes, opening the site in your browser.
280+
246281
\b
247282
Examples:
248283
great-docs build # Full build with API refresh
@@ -251,19 +286,58 @@ def build(
251286
great-docs build --versions 0.3,dev # Build specific versions only
252287
great-docs build --latest-only # Build only the latest version
253288
great-docs build --project-path ../pkg
289+
great-docs build --from-repo https://github.com/owner/pkg.git
290+
great-docs build --from-repo git@github.com:owner/pkg.git --branch v1.0
291+
great-docs build --from-repo https://github.com/owner/pkg.git --output-dir ./site
292+
great-docs build --from-repo https://github.com/owner/pkg.git --shallow
293+
great-docs build --from-repo https://github.com/owner/pkg.git --preview
254294
"""
255295
try:
256-
docs = GreatDocs(project_path=project_path)
257-
# Parse version filter if provided
258-
version_tags = None
259-
if version_filter:
260-
version_tags = [v.strip() for v in version_filter.split(",") if v.strip()]
261-
docs.build(
262-
watch=watch,
263-
refresh=not no_refresh,
264-
version_tags=version_tags,
265-
latest_only=latest_only,
266-
)
296+
if from_repo:
297+
# Remote build: clone, install, build, copy output
298+
if project_path:
299+
click.echo(
300+
"Warning: --project-path is ignored when --from-repo is used",
301+
err=True,
302+
)
303+
if watch:
304+
click.echo("Error: --watch is not supported with --from-repo", err=True)
305+
sys.exit(1)
306+
version_tags = None
307+
if version_filter:
308+
version_tags = [v.strip() for v in version_filter.split(",") if v.strip()]
309+
GreatDocs.build_from_repo(
310+
from_repo,
311+
branch=branch,
312+
output_dir=output_dir,
313+
refresh=not no_refresh,
314+
version_tags=version_tags,
315+
latest_only=latest_only,
316+
shallow=shallow,
317+
)
318+
if preview_after:
319+
site_path = output_dir or str(Path.cwd() / "great-docs" / "_site")
320+
GreatDocs.preview_site(site_path)
321+
else:
322+
if branch:
323+
click.echo("Warning: --branch is ignored without --from-repo", err=True)
324+
if shallow:
325+
click.echo("Warning: --shallow is ignored without --from-repo", err=True)
326+
if output_dir:
327+
click.echo("Warning: --output-dir is ignored without --from-repo", err=True)
328+
if preview_after:
329+
click.echo("Warning: --preview is ignored without --from-repo", err=True)
330+
docs = GreatDocs(project_path=project_path)
331+
# Parse version filter if provided
332+
version_tags = None
333+
if version_filter:
334+
version_tags = [v.strip() for v in version_filter.split(",") if v.strip()]
335+
docs.build(
336+
watch=watch,
337+
refresh=not no_refresh,
338+
version_tags=version_tags,
339+
latest_only=latest_only,
340+
)
267341
except KeyboardInterrupt:
268342
click.echo("\n👋 Stopped watching")
269343
except Exception as e:
@@ -313,7 +387,13 @@ def uninstall(project_path: str | None) -> None:
313387
show_default=True,
314388
help="Port for the local preview server",
315389
)
316-
def preview(project_path: str | None, port: int) -> None:
390+
@click.option(
391+
"--site-dir",
392+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
393+
default=None,
394+
help="Path to a pre-built site directory to serve (bypasses project detection)",
395+
)
396+
def preview(project_path: str | None, port: int, site_dir: str | None) -> None:
317397
"""Preview your documentation locally.
318398
319399
Starts a local HTTP server and opens the built documentation site in your
@@ -322,14 +402,26 @@ def preview(project_path: str | None, port: int) -> None:
322402
The site is served from great-docs/_site/. Use 'great-docs build' to
323403
rebuild if you've made changes.
324404
405+
Use --site-dir to preview a site from any directory (e.g. output from
406+
a --from-repo build).
407+
325408
\b
326409
Examples:
327410
great-docs preview # Preview on port 3000
328411
great-docs preview --port 8080 # Preview on port 8080
412+
great-docs preview --site-dir /tmp/weathervault-site
329413
"""
330414
try:
331-
docs = GreatDocs(project_path=project_path)
332-
docs.preview(port=port)
415+
if site_dir:
416+
if project_path:
417+
click.echo(
418+
"Warning: --project-path is ignored when --site-dir is used",
419+
err=True,
420+
)
421+
GreatDocs.preview_site(site_dir, port=port)
422+
else:
423+
docs = GreatDocs(project_path=project_path)
424+
docs.preview(port=port)
333425
except KeyboardInterrupt:
334426
click.echo("\n👋 Server stopped")
335427
except Exception as e:

0 commit comments

Comments
 (0)