diff --git a/README.md b/README.md index 5f17442b..f5691187 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ A modern [Copier template](https://github.com/copier-org/copier) for scaffolding - ♻️ Continuous integration with [GitHub Actions](https://docs.github.com/en/actions) or [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) - 🧪 Test coverage with [Coverage.py](https://github.com/nedbat/coveragepy) - 🧰 Dependency updates with [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates) +- 📚 Documentation with [MkDocs](https://github.com/mkdocs/mkdocs) ## ✨ Using @@ -91,6 +92,19 @@ To migrate a project from Cookiecutter to Copier, follow these steps: 5. Create a PR from your branch, review it, and merge it! +### Build and publish your Python project's docs + +To build and serve your Python project's docs, run: + +```sh +poe docs --serve +``` + +If your project is on GitHub, your docs will be published automatically to GitHub Pages every time you update the default branch. You can view the docs by clicking on the ![Documentation](https://img.shields.io/static/v1?label=Documentation&message=View&color=blue&logo=readme&logoColor=white)] badge in your project's README. + +> [!TIP] +> Make sure to [configure the source of your project's GitHub Pages as GitHub Actions in your project settings](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow) to allow the GitHub Actions workflow to publish your docs. + ## Contributing
diff --git a/copier.yml b/copier.yml index bb0c82da..44d7c933 100644 --- a/copier.yml +++ b/copier.yml @@ -98,3 +98,8 @@ project_name_kebab_case: project_name_snake_case: when: false default: "{{ project_name | lower | replace(' ', '_') }}" + +documentation_url: + when: false + default: "{% if ci == 'github' %}https://{{ project_url.rstrip('/').split('/')[-2] }}.github.io/{{ project_url.rstrip('/').split('/')[-1] }}{% else %}{{ project_url }}{% endif %}" + diff --git a/template/.gitignore.jinja b/template/.gitignore.jinja index 253d2bad..fe2b5e5d 100644 --- a/template/.gitignore.jinja +++ b/template/.gitignore.jinja @@ -33,6 +33,9 @@ notebooks/ # mise mise.local.toml +# MkDocs +site/ + # mypy .dmypy.json .mypy_cache/ diff --git a/template/README.md.jinja b/template/README.md.jinja index 4c4487f4..1451740c 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -1,4 +1,4 @@ -[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE3IDE2VjdsLTYgNU0yIDlWOGwxLTFoMWw0IDMgOC04aDFsNCAyIDEgMXYxNGwtMSAxLTQgMmgtMWwtOC04LTQgM0gzbC0xLTF2LTFsMy0zIi8+PC9zdmc+)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url={{ project_url }}){% if ci == 'github' %} [![Open in GitHub Codespaces](https://img.shields.io/static/v1?label=GitHub%20Codespaces&message=Open&color=blue&logo=github)](https://github.com/codespaces/new/{{ project_url.replace("https://github.com/", "") }}){% endif %} +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE3IDE2VjdsLTYgNU0yIDlWOGwxLTFoMWw0IDMgOC04aDFsNCAyIDEgMXYxNGwtMSAxLTQgMmgtMWwtOC04LTQgM0gzbC0xLTF2LTFsMy0zIi8+PC9zdmc+)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url={{ project_url }}){% if ci == 'github' %} [![Open in GitHub Codespaces](https://img.shields.io/static/v1?label=GitHub%20Codespaces&message=Open&color=blue&logo=github)](https://github.com/codespaces/new/{{ project_url.replace("https://github.com/", "") }}){% endif %}{% if ci == 'github' %} [![Documentation](https://img.shields.io/static/v1?label=Documentation&message=View&color=blue&logo=readme&logoColor=white)]({{ documentation_url }}){% endif %} # {{ project_name }} diff --git a/template/docs/index.md.jinja b/template/docs/index.md.jinja new file mode 100644 index 00000000..3f65d4f2 --- /dev/null +++ b/template/docs/index.md.jinja @@ -0,0 +1,3 @@ +# {{ project_name }} + +{{ project_description }} diff --git a/template/docs/{% if project_type == 'package' %}reference.md{% endif %}.jinja b/template/docs/{% if project_type == 'package' %}reference.md{% endif %}.jinja new file mode 100644 index 00000000..fd2ee526 --- /dev/null +++ b/template/docs/{% if project_type == 'package' %}reference.md{% endif %}.jinja @@ -0,0 +1,3 @@ +# Reference + +::: {{ project_name_snake_case }} diff --git a/template/mkdocs.yml.jinja b/template/mkdocs.yml.jinja new file mode 100644 index 00000000..8c764426 --- /dev/null +++ b/template/mkdocs.yml.jinja @@ -0,0 +1,41 @@ +site_name: {{ project_name }} +site_description: {{ project_description }} +site_url: {{ documentation_url }} +repo_url: {{ project_url }} +repo_name: {{ project_url.rstrip('/').split('/')[-2:] | join('/') }} +{%- if typing == 'strict' %} + +strict: true + +validation: + omitted_files: warn + absolute_links: warn + unrecognized_links: warn + anchors: warn +{%- endif %} + +theme: + name: material + +nav: + - Home: index.md +{%- if project_type == 'package' %} + - Reference: reference.md + +watch: + - src +{%- endif %} + +plugins: + - search +{%- if project_type == 'package' %} + - mkdocstrings: + handlers: + python: + options: + docstring_style: numpy +{%- endif %} + +markdown_extensions: + - pymdownx.highlight + - pymdownx.superfences diff --git a/template/pyproject.toml.jinja b/template/pyproject.toml.jinja index 712dd299..8b638d43 100644 --- a/template/pyproject.toml.jinja +++ b/template/pyproject.toml.jinja @@ -36,7 +36,7 @@ source = "{{ project_url }}" changelog = "{{ project_url.rstrip('/') }}/{% if ci == 'gitlab' %}-/{% endif %}blob/main/CHANGELOG.md" {%- endif %} releasenotes = "{{ project_url.rstrip('/') }}/{% if ci == 'gitlab' %}-/{% endif %}releases" -documentation = "{{ project_url }}" +documentation = "{{ documentation_url }}" issues = "{{ project_url.rstrip('/') }}/{% if ci == 'gitlab' %}-/{% endif %}issues" [dependency-groups] # https://docs.astral.sh/uv/concepts/projects/dependencies/#development-dependencies @@ -49,8 +49,9 @@ dev = [ "ipython (>=8.18.0)", "ipywidgets (>=8.1.2)", "mypy (>=1.14.1)", - "pdoc (>=15.0.1)", + "mkdocs-material (>=9.5.21)", {%- if project_type == 'package' %} + "mkdocstrings[python] (>=0.26.2)", "poethepoet (>=0.32.1)", {%- endif %} "pre-commit (>=4.0.1)", @@ -154,6 +155,23 @@ convention = "numpy" type = "simple" [tool.poe.tasks] + + [tool.poe.tasks.docs] + help = "Build or serve the documentation" + shell = """ + if [ $serve ] + then { + mkdocs serve + } else { + mkdocs build + } fi + """ + + [[tool.poe.tasks.docs.args]] + help = "Serve the documentation locally with live reload" + type = "boolean" + name = "serve" + options = ["--serve"] {%- if with_fastapi_api %} [tool.poe.tasks.serve] @@ -207,27 +225,6 @@ type = "simple" cmd = "echo 'Serving app (placeholder)...'" {%- endif %} - [tool.poe.tasks.docs] - help = "Generate this {{ project_type }}'s docs" - cmd = """ - pdoc - --docformat $docformat - --output-directory $outputdirectory - {{ project_name_snake_case }} - """ - - [[tool.poe.tasks.docs.args]] - help = "The docstring style (default: numpy)" - name = "docformat" - options = ["--docformat"] - default = "numpy" - - [[tool.poe.tasks.docs.args]] - help = "The output directory (default: docs)" - name = "outputdirectory" - options = ["--output-directory"] - default = "docs" - [tool.poe.tasks.lint] help = "Lint this {{ project_type }}" cmd = """ diff --git a/template/{% if ci == 'github' %}.github{% endif %}/workflows/docs.yml.jinja b/template/{% if ci == 'github' %}.github{% endif %}/workflows/docs.yml.jinja new file mode 100644 index 00000000..07e118c7 --- /dev/null +++ b/template/{% if ci == 'github' %}.github{% endif %}/workflows/docs.yml.jinja @@ -0,0 +1,44 @@ +name: Documentation + +on: + push: + branches: [main] + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + environment: + name: github-pages + url: ${{ "{{" }} steps.deployment.outputs.page_url {{ "}}" }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install uv + uses: astral-sh/setup-uv@v6 + + - name: Build docs + run: uv run mkdocs build + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@v4 + with: + path: site + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file