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
1 change: 1 addition & 0 deletions docs/concepts/generated-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Generated projects typically include:
- **CLI:** If a CLI name is provided, the template generates a Typer-based CLI.
- **FastAPI:** If FastAPI is enabled, the template generates `src/<package>/app/`.
- **Datasets:** If dataset support is enabled, the template generates dataset config and the selected loaders under `src/<package>/datasets/`.
- **Paper:** If LaTeX paper support is enabled, the template generates a `paper/` manuscript scaffold with root `make paper` targets.
6 changes: 6 additions & 0 deletions docs/template-prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ Repoman prompts for:
| ------------------ | --------------------------------- | ------- |
| `python_notebooks` | Include Jupyter notebooks support | `false` |

### Paper

| Prompt | Description | Default |
| ------------- | -------------------------------------------- | ------- |
| `latex_paper` | Include a LaTeX paper scaffold under `paper/` | `false` |

### Datasets

| Prompt | Description | Default |
Expand Down
2 changes: 2 additions & 0 deletions docs/template-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- **Datasets:** If `dataset_enabled` is true, the template generates `config/dataset_config.json`, `src/{{ python_package_import_name }}/config/dataset_config.py`, and the selected dataset loaders/adapters under `src/{{ python_package_import_name }}/datasets/`.
- **Docs-only:** If `docs_only` is true, source package and test files are omitted.
- **Notebooks:** If `python_notebooks` is true, the template generates a `notebooks/` folder.
- **Paper:** If `latex_paper` is true, the template generates a `paper/` folder with a LaTeX manuscript scaffold and Make targets.
- **C++:** The bundled `cpp_template` is a separate Meson-based template with `include/`, `src/`, `tests/`, `examples/`, Doxygen hooks, and the same repoman Make target names used by CI.

## High-level generated layout
Expand All @@ -20,6 +21,7 @@ my_project/
├── docs/
├── make_cmds/
├── notebooks/
├── paper/
├── scripts/
├── src/
│ └── <package>/
Expand Down
5 changes: 5 additions & 0 deletions src/repoman/copier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ python_notebooks:
help: Include Jupyter notebooks support (notebooks folder and ipykernel)
default: false

latex_paper:
type: bool
help: Include a LaTeX paper scaffold under paper/
default: false

# FastAPI application (when fastapi_enabled)
fastapi_enabled:
type: bool
Expand Down
4 changes: 4 additions & 0 deletions src/repoman/main_template/.gitignore.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
/htmlcov/
/site/
uv.lock
{% if latex_paper %}
/paper/build/
/paper/main.pdf
{% endif %}

# cache
.cache/
Expand Down
3 changes: 3 additions & 0 deletions src/repoman/main_template/Makefile.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ include make_cmds/prod.mk
{% if python_notebooks %}
include make_cmds/notebooks.mk
{% endif %}
{% if latex_paper %}
include make_cmds/paper.mk
{% endif %}

##############
# Versioning #
Expand Down
14 changes: 14 additions & 0 deletions src/repoman/main_template/README.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,17 @@ make prod

`make prod` uses `docker compose up --build`, exposes the API on `http://localhost:8000`, and passes `OPENAI_API_KEY` into the container. Exporting `OPENAI_API_TOKEN` also works because the Make target normalizes it to `OPENAI_API_KEY` before Compose starts.
{% endif %}
{% if latex_paper %}

## Paper

The LaTeX manuscript scaffold lives in `paper/`.

Build it with:

```bash
make paper
```

This target requires a TeX distribution with `latexmk`.
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,10 @@ When dataset support is enabled, dataset loaders and types live in
`src/{{ python_package_import_name }}/datasets/` and use
`config/dataset_config.json` plus `DatasetConfig` for defaults and overrides.
{% endif %}
{% if latex_paper %}
## Paper

When the LaTeX paper scaffold is enabled, manuscript sources live under
`paper/`. The root `make paper`, `make paper-watch`, and `make paper-clean`
targets delegate to `paper/Makefile`.
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#######################
# Paper #
#######################

.PHONY: paper
paper: ## Build the LaTeX paper PDF.
$(MAKE) -C paper pdf

.PHONY: paper-watch
paper-watch: ## Continuously rebuild the LaTeX paper PDF.
$(MAKE) -C paper watch

.PHONY: paper-clean
paper-clean: ## Remove LaTeX build artifacts.
$(MAKE) -C paper clean
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$pdf_mode = 1;
$bibtex_use = 2;
$interaction = "nonstopmode";
$out_dir = "build";
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
MAIN := main
BUILD_DIR := build
PDF := $(MAIN).pdf

.PHONY: all
all: pdf

.PHONY: pdf
pdf: ## Build $(PDF) with latexmk.
latexmk -pdf -interaction=nonstopmode -halt-on-error -outdir=$(BUILD_DIR) $(MAIN).tex
cp $(BUILD_DIR)/$(PDF) $(PDF)

.PHONY: watch
watch: ## Rebuild $(PDF) whenever sources change.
latexmk -pdf -pvc -interaction=nonstopmode -halt-on-error -outdir=$(BUILD_DIR) $(MAIN).tex

.PHONY: clean
clean: ## Remove LaTeX build artifacts.
latexmk -C -outdir=$(BUILD_DIR) $(MAIN).tex
rm -rf $(BUILD_DIR)

.PHONY: distclean
distclean: clean ## Remove generated PDF.
rm -f $(PDF)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Paper

This folder contains the LaTeX manuscript scaffold for `{{ project_name }}`.

## Build

Install a TeX distribution with `latexmk`, then run:

```bash
make paper
```

From this folder, you can also run:

```bash
make pdf
make watch
make clean
```

The root `make paper` target delegates to `paper/Makefile` and writes
`paper/main.pdf`.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{% set paper_title = project_name | replace('-', ' ') | title -%}
\documentclass[11pt]{article}

\usepackage[margin=1in]{geometry}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage{microtype}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{booktabs}
\usepackage[hidelinks]{hyperref}
\usepackage[backend=biber,style=numeric,sorting=none]{biblatex}

\addbibresource{references.bib}
{% raw -%}
\graphicspath{{figures/}}
{% endraw %}

\title{ {{- paper_title -}} }
\author{ {{- author_fullname -}} }
\date{\today}

\begin{document}

\maketitle

\begin{abstract}
\input{sections/abstract}
\end{abstract}

\input{sections/introduction}
\input{sections/methods}
\input{sections/results}
\input{sections/discussion}

\printbibliography

\end{document}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@misc{project,
author = { {{- author_fullname -}} },
title = { {{- project_name | replace('-', ' ') | title -}} },
year = { {{- copyright_date -}} },
note = {Project manuscript scaffold}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Summarize the problem, approach, main result, and implication in one concise paragraph.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\section{Discussion}

Interpret the results, identify limitations, and outline next steps.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\section{Introduction}

Introduce the problem, motivate why it matters, and define the contribution.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\section{Methods}

Describe the data, assumptions, model, implementation, and evaluation protocol.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\section{Results}

Present the key findings with tables, figures, and uncertainty where appropriate.
3 changes: 3 additions & 0 deletions src/repoman/resources/copier_answers_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ container_registry: ""
# Notebooks
python_notebooks: false

# Paper
latex_paper: false

# FastAPI application
fastapi_enabled: true
fastapi_docs_url: "/docs"
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/default_copier_answers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ container_registry: ""
# Notebooks
python_notebooks: true

# Paper
latex_paper: true

# FastAPI application
fastapi_enabled: true
fastapi_docs_url: "/docs"
Expand Down
1 change: 1 addition & 0 deletions tests/template_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def instantiate_template(
"insiders": False,
"public_release": False,
"python_notebooks": False,
"latex_paper": False,
}

# Merge answers file data first (if provided), then provided copier_data (highest priority)
Expand Down
43 changes: 43 additions & 0 deletions tests/test_template/test_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,49 @@ def test_instantiated_template_notebook_executes(setup_template: Any) -> None:
)


def test_latex_paper_template_renders_paper_folder_only_when_enabled(tmp_path: Path) -> None:
"""LaTeX paper scaffold files should be controlled by latex_paper."""
answers_file = Path(__file__).parent.parent / "fixtures" / "default_copier_answers.yml"

disabled_dir = instantiate_template(
output_dir=tmp_path / "disabled",
project_name="test-project",
answers_file=answers_file,
copier_data={"latex_paper": False},
)
assert not (disabled_dir / "paper").exists()
assert not (disabled_dir / "make_cmds" / "paper.mk").exists()
assert "include make_cmds/paper.mk" not in _read_text(disabled_dir / "Makefile")
assert "/paper/build/" not in _read_text(disabled_dir / ".gitignore")

enabled_dir = instantiate_template(
output_dir=tmp_path / "enabled",
project_name="paper-project",
answers_file=answers_file,
copier_data={"latex_paper": True},
)
paper_dir = enabled_dir / "paper"
assert (paper_dir / "main.tex").exists()
assert (paper_dir / ".latexmkrc").exists()
assert (paper_dir / "references.bib").exists()
assert (paper_dir / "sections" / "introduction.tex").exists()
assert (paper_dir / "figures" / ".gitkeep").exists()

makefile = _read_text(enabled_dir / "Makefile")
paper_makefile = _read_text(enabled_dir / "make_cmds" / "paper.mk")
paper_readme = _read_text(paper_dir / "README.md")
main_tex = _read_text(paper_dir / "main.tex")
references = _read_text(paper_dir / "references.bib")

assert "include make_cmds/paper.mk" in makefile
assert "paper: ## Build the LaTeX paper PDF." in paper_makefile
assert "make paper" in paper_readme
assert r"\title{Paper Project}" in main_tex
assert r"\input{sections/introduction}" in main_tex
assert "title = {Paper Project}" in references
assert "/paper/build/" in _read_text(enabled_dir / ".gitignore")


def test_instantiated_template_without_fastapi(tmp_path: Path) -> None:
"""When fastapi_enabled is false, no app folder is created and CI still passes."""
answers_file = Path(__file__).parent.parent / "fixtures" / "default_copier_answers.yml"
Expand Down
Loading