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
68 changes: 68 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Documentation

on:
push:
branches: ["main"]
paths:
- ".github/workflows/pages.yml"
- ".python-version"
- "docs/**"
- "mkdocs.yml"
- "pyproject.toml"
- "uv.lock"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
name: Build documentation
runs-on: ubuntu-latest
permissions:
contents: read
pages: read

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Install uv
uses: astral-sh/setup-uv@v8.1.0

- name: Set up Python
run: uv python install

- name: Install dependencies
run: uv sync --locked --group dev

- name: Configure GitHub Pages
uses: actions/configure-pages@v5

- name: Build documentation site
run: uv run mkdocs build --strict

- name: Upload GitHub Pages artifact
uses: actions/upload-pages-artifact@v5
with:
path: site

deploy:
name: Deploy documentation
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ merging are disabled to keep that history consistent.
After a pull request is merged, GitHub deletes its remote branch automatically.
Delete the corresponding local branch after updating `main`.

When relevant documentation files change, the separate `Documentation`
workflow publishes the reviewed site after the merge. This deployment is not a
pull request check and does not replace the required `Quality checks` status.

## Documentation terminology

Use the official spelling of tool names: `uv`, pytest, mypy, `rumdl`, and
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Modern Python Project Guide

[![CI](https://github.com/michalmaj/modern-python-project-guide/actions/workflows/ci.yml/badge.svg)](https://github.com/michalmaj/modern-python-project-guide/actions/workflows/ci.yml)
[![Documentation](https://github.com/michalmaj/modern-python-project-guide/actions/workflows/pages.yml/badge.svg)](https://michalmaj.github.io/modern-python-project-guide/)

A practical, beginner-friendly guide to building a clean Python project with
`uv`, `pytest`, Ruff, mypy, `rumdl`, MkDocs, `pyproject.toml`, GitHub Actions,
Expand All @@ -17,6 +18,8 @@ tool gradually and shows how the pieces fit together in a maintainable project.
- **Learn the complete workflow:** start with
[Why This Guide Exists](docs/00_why_this_guide.md) and follow the main learning
path below.
- **Browse the published guide:** open the
[documentation site](https://michalmaj.github.io/modern-python-project-guide/).
- **Find a command or solve a problem:** jump to the
[reference material](#reference-material).

Expand All @@ -34,6 +37,7 @@ By following the guide, you will learn how to:
- check type annotations with mypy,
- lint Markdown documentation with `rumdl`,
- preview and validate a documentation site with MkDocs,
- publish documentation safely with GitHub Pages,
- automate fast checks with `pre-commit` hooks,
- run automated quality checks in GitHub Actions,
- work with branches, commits, and pull requests.
Expand Down Expand Up @@ -61,7 +65,8 @@ understand why each tool and file is introduced.
13. [`pre-commit` hooks](docs/13_pre_commit_hooks.md)
14. [Markdown linting with rumdl](docs/14_markdown_linting.md)
15. [Documentation site with MkDocs](docs/15_documentation_site_with_mkdocs.md)
16. [Project checklist](docs/09_checklist.md)
16. [Publishing with GitHub Pages](docs/16_publishing_with_github_pages.md)
17. [Project checklist](docs/09_checklist.md)

## Reference material

Expand Down
7 changes: 6 additions & 1 deletion docs/01_project_structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ The repository currently uses this structure:
modern-python-project-guide/
├── .github/
│ ├── workflows/
│ │ └── ci.yml
│ │ ├── ci.yml
│ │ └── pages.yml
│ └── pull_request_template.md
├── docs/
│ ├── 00_why_this_guide.md
Expand Down Expand Up @@ -107,8 +108,12 @@ Example:
```text
.github/pull_request_template.md
.github/workflows/ci.yml
.github/workflows/pages.yml
```

The CI workflow validates pull requests and `main`. The Pages workflow publishes
the documentation after relevant changes reach `main`.

## mkdocs.yml

The `mkdocs.yml` file defines the documentation site, including its navigation,
Expand Down
5 changes: 5 additions & 0 deletions docs/06_github_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ The workflow builds the MkDocs site with strict validation:
The step validates navigation and rendering without publishing the generated
site. The `site/` output directory remains an ignored local artifact.

Publishing is handled by the separate `.github/workflows/pages.yml` workflow
after relevant changes reach `main`. Pull requests never receive deployment
permissions. See [Publishing with GitHub Pages](16_publishing_with_github_pages.md)
for the build, artifact, environment, and permission flow.

## Tests and coverage

The workflow runs tests and prints a coverage report:
Expand Down
17 changes: 16 additions & 1 deletion docs/09_checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ When the documentation set grows, a generated site can improve navigation:
- [ ] generated `site/` files are ignored
- [ ] strict site builds run locally and in CI
- [ ] building and publishing are treated as separate operations
- [ ] a dedicated deployment workflow publishes only from `main`
- [ ] generated output is uploaded as an artifact instead of committed
- [ ] deployment permissions are limited to the deployment job
- [ ] the public site contains no secrets or private material

Preview and validate the site with:

Expand All @@ -229,6 +233,17 @@ The project should run checks automatically in CI:
- [ ] CI builds a wheel and source distribution
- [ ] CI status is visible in the README

## Continuous deployment

If the documentation is published automatically:

- [ ] GitHub Pages uses **GitHub Actions** as its source
- [ ] the deployment workflow runs after relevant changes reach `main`
- [ ] pull requests validate the site without publishing it
- [ ] build and deploy jobs pass the generated site as an artifact
- [ ] the deployment uses the `github-pages` environment
- [ ] the published site is checked after deployment

CI helps protect the main branch from broken changes.

## Git workflow
Expand Down Expand Up @@ -355,5 +370,5 @@ Let the project grow gradually.

## Continue

- [Previous: Documentation Site with MkDocs](15_documentation_site_with_mkdocs.md)
- [Previous: Publishing with GitHub Pages](16_publishing_with_github_pages.md)
- [Back to documentation home](index.md)
13 changes: 7 additions & 6 deletions docs/15_documentation_site_with_mkdocs.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,14 @@ The documentation checks have separate responsibilities:

No single tool replaces the others.

## Build is not deployment
## Build and deployment are separate

The current CI job only proves that the site can be generated. It does not
publish HTML, change GitHub Pages settings, or require deployment permissions.
The `Quality checks` CI job only proves that the site can be generated. It does
not publish HTML or require deployment permissions.

Publishing should be evaluated and implemented separately after the local site
has been reviewed.
After a reviewed change reaches `main`, a separate workflow publishes the
generated site. Keeping these operations separate prevents pull requests from
changing the public documentation.

## Rule of thumb

Expand All @@ -118,5 +119,5 @@ Use the generated site to improve navigation, search, and previewing.
## Continue

- [Previous: Markdown Linting with rumdl](14_markdown_linting.md)
- [Next: Project Checklist](09_checklist.md)
- [Next: Publishing with GitHub Pages](16_publishing_with_github_pages.md)
- [Back to documentation home](index.md)
116 changes: 116 additions & 0 deletions docs/16_publishing_with_github_pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Publishing with GitHub Pages

A strict MkDocs build proves that the documentation can be generated. GitHub
Pages makes that generated site available to readers on the web.

This project publishes the site at:

<https://michalmaj.github.io/modern-python-project-guide/>

## Build and deployment remain separate

The repository has two workflows with different responsibilities:

- `.github/workflows/ci.yml` validates every pull request and push to `main`,
- `.github/workflows/pages.yml` publishes documentation after relevant changes
reach `main`.

A pull request therefore cannot update the public site. It must first pass the
normal review and `Quality checks` requirement. The merge commit then starts the
documentation workflow.

## One-time repository setting

The repository owner must enable GitHub Pages once:

1. Open the repository **Settings**.
2. Select **Pages** under **Code, planning, and automation**.
3. Under **Build and deployment**, set **Source** to **GitHub Actions**.

The workflow does not publish from a `gh-pages` branch and does not commit the
generated `site/` directory.

## When deployment runs

The documentation workflow runs when a push to `main` changes its own workflow,
the Python version, documentation sources, MkDocs configuration, or dependency
files. It can also be started manually from the **Actions** tab.

The path filter avoids redeploying an unchanged site after unrelated source-code
changes. Manual dispatch remains available for recovery or verification.

## Build job

The `build` job recreates the site from a clean checkout:

1. check out the repository,
2. install `uv` and the configured Python version,
3. install locked development dependencies,
4. configure GitHub Pages,
5. run `uv run mkdocs build --strict`,
6. upload `site/` as a GitHub Pages artifact.

The artifact is the boundary between building and deploying. It contains the
generated static site, but it is not committed to the repository.

## Deploy job

The `deploy` job waits for the build job. It deploys the uploaded artifact to
the `github-pages` environment and reports the resulting public URL.

The workflow grants only the permissions it needs:

- `contents: read` reads repository files,
- `pages: write` creates the Pages deployment,
- `id-token: write` lets GitHub verify the deployment with OpenID Connect.

The write permissions belong only to the deploy job. The normal CI workflow
does not receive them.

## Why use an environment?

GitHub Pages deployments use the `github-pages` environment. It records
deployment history and can enforce protection rules.

The workflow also uses a `pages` concurrency group. A running production
deployment is allowed to finish instead of being cancelled by a newer run.

## Verify a deployment

After merging a documentation change:

1. open the repository **Actions** tab,
2. select the **Documentation** workflow,
3. confirm that **Build documentation** and **Deploy documentation** passed,
4. open the deployment URL shown by the deploy job,
5. verify the changed page and navigation.

The existing `Quality checks` status remains the branch-protection requirement.
Deployment happens after merge, so a deployment failure should be fixed with a
new pull request rather than by weakening that requirement.

## Public output and secrets

Everything in the generated site is public. Documentation sources and build
configuration must not contain credentials, private notes, or other sensitive
information.

This workflow needs no repository secrets. GitHub supplies a short-lived token
with the declared permissions.

## Custom domains are separate

This project uses the default `github.io` address. A custom domain would require
additional DNS and repository settings and is intentionally outside this setup.

## Rule of thumb

Validate on pull requests. Publish only from the protected default branch.

Keep generated files out of Git and deploy a reproducible artifact instead.

## Continue

- [Previous: Documentation Site with MkDocs](15_documentation_site_with_mkdocs.md)
- [Next: Project Checklist](09_checklist.md)
- [Back to documentation home](index.md)
8 changes: 3 additions & 5 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ These parts are already included in the repository.
- [x] Keep Markdown linting separate from link checks and human review
- [x] Add an MkDocs site with explicit navigation and strict CI builds
- [x] Keep documentation sources readable without the generated site
- [x] Publish the documentation site with GitHub Pages
- [x] Keep validation and deployment in separate workflows

## Next

Expand Down Expand Up @@ -169,10 +171,6 @@ They may be added later as separate chapters.

- [ ] Explain publishing to PyPI

### Documentation site

- [ ] Decide whether to publish the MkDocs site with GitHub Pages

### Release automation

- [ ] Explain versioning
Expand All @@ -192,7 +190,7 @@ These topics were deliberately excluded from the original foundation:
- Docker,
- publishing to PyPI,
- release automation,
- documentation site generation,
- documentation site generation and deployment,
- pre-commit hooks,
- coverage gates,
- complex multi-job CI,
Expand Down
14 changes: 11 additions & 3 deletions docs/common_questions.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,22 @@ They point readers toward the same material, but they appear in different
contexts. Keeping the site landing page inside `docs/` also follows MkDocs'
normal source layout.

## Why does CI build the site without publishing it?
## Why does pull request CI build the site without publishing it?

A strict build verifies configuration, navigation, links, anchors, and
rendering without changing external state.

Publishing requires a separate deployment workflow, permissions, and GitHub
Pages settings. Those decisions should be reviewed independently after the
local site has proved useful.
Pages settings. In this repository, that workflow runs only after relevant
changes reach `main`, so a pull request cannot update the public site.

## Where is the documentation site published?

The site is available at
<https://michalmaj.github.io/modern-python-project-guide/>.

The `Documentation` workflow builds it from the same Markdown sources and
deploys a generated artifact. The generated `site/` directory is not committed.

## Rule of thumb

Expand Down
Loading
Loading