From e9253628d206d30f4c01cead4d66cbf91a59086e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Maj?= Date: Wed, 30 Sep 2026 11:56:54 +0200 Subject: [PATCH] docs: publish MkDocs site with Pages --- .github/workflows/pages.yml | 68 +++++++++++++ CONTRIBUTING.md | 4 + README.md | 7 +- docs/01_project_structure.md | 7 +- docs/06_github_actions.md | 5 + docs/09_checklist.md | 17 +++- docs/15_documentation_site_with_mkdocs.md | 13 +-- docs/16_publishing_with_github_pages.md | 116 ++++++++++++++++++++++ docs/ROADMAP.md | 8 +- docs/common_questions.md | 14 ++- docs/github_actions_logs.md | 27 +++++ docs/glossary.md | 8 ++ docs/index.md | 6 +- docs/troubleshooting.md | 26 +++++ mkdocs.yml | 2 + 15 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/pages.yml create mode 100644 docs/16_publishing_with_github_pages.md diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..3869da8 --- /dev/null +++ b/.github/workflows/pages.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24219f7..6de8fee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/README.md b/README.md index 64ae979..b4a01d5 100644 --- a/README.md +++ b/README.md @@ -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, @@ -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). @@ -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. @@ -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 diff --git a/docs/01_project_structure.md b/docs/01_project_structure.md index ea4d95d..55658d2 100644 --- a/docs/01_project_structure.md +++ b/docs/01_project_structure.md @@ -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 @@ -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, diff --git a/docs/06_github_actions.md b/docs/06_github_actions.md index bf3a628..3b0706e 100644 --- a/docs/06_github_actions.md +++ b/docs/06_github_actions.md @@ -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: diff --git a/docs/09_checklist.md b/docs/09_checklist.md index 459b180..9257674 100644 --- a/docs/09_checklist.md +++ b/docs/09_checklist.md @@ -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: @@ -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 @@ -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) diff --git a/docs/15_documentation_site_with_mkdocs.md b/docs/15_documentation_site_with_mkdocs.md index fcb6712..67b9047 100644 --- a/docs/15_documentation_site_with_mkdocs.md +++ b/docs/15_documentation_site_with_mkdocs.md @@ -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 @@ -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) diff --git a/docs/16_publishing_with_github_pages.md b/docs/16_publishing_with_github_pages.md new file mode 100644 index 0000000..6e6acf8 --- /dev/null +++ b/docs/16_publishing_with_github_pages.md @@ -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: + + + +## 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) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 98d9c62..05b1946 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -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 @@ -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 @@ -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, diff --git a/docs/common_questions.md b/docs/common_questions.md index 5d4c02c..61bbc4d 100644 --- a/docs/common_questions.md +++ b/docs/common_questions.md @@ -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 +. + +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 diff --git a/docs/github_actions_logs.md b/docs/github_actions_logs.md index 7fee454..598b481 100644 --- a/docs/github_actions_logs.md +++ b/docs/github_actions_logs.md @@ -84,6 +84,17 @@ Do not debug everything at once. Start with the failed step. +The separate `Documentation` workflow runs after relevant changes reach `main`. +It has two jobs: + +```text +Build documentation +Deploy documentation +``` + +The build job creates and uploads the site artifact. The deploy job publishes +that artifact to the `github-pages` environment. + ## Step: Checkout repository ### What it does @@ -811,6 +822,22 @@ CI checks repetitive things. Humans still review meaning and quality. +## What a green documentation deployment means + +A green `Documentation` workflow means: + +- the site was built strictly from locked dependencies, +- the generated `site/` directory was uploaded as an artifact, +- GitHub Pages accepted the deployment, +- GitHub reported a public deployment URL. + +It does not prove that every page looks or reads as intended. Open the published +site and inspect the changed page after deployment. + +If `Build documentation` fails, reproduce the strict build locally. If `Deploy +documentation` fails, inspect Pages settings, workflow permissions, the +`github-pages` environment, and the first useful deployment error. + ## Rule of thumb When CI fails, ask: diff --git a/docs/glossary.md b/docs/glossary.md index 9c3df89..82d150f 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -213,6 +213,14 @@ uv run mkdocs build --strict The build reads `mkdocs.yml` and the Markdown files in `docs/`. It writes generated HTML to the ignored `site/` directory. +## GitHub Pages + +GitHub Pages hosts static websites generated from repository content. + +In this guide, a dedicated GitHub Actions workflow builds the MkDocs site after +relevant changes reach `main`, uploads `site/` as an artifact, and deploys it to +the `github-pages` environment. + ## Package The word “package” can mean different things in Python. diff --git a/docs/index.md b/docs/index.md index f32df97..1777395 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,6 +5,7 @@ modern tools and a pull-request-based workflow. The same Markdown files remain readable directly on GitHub. MkDocs adds site navigation, search, and a local preview without replacing the repository README. +Reviewed changes are published here from the protected `main` branch. ## Choose your path @@ -24,9 +25,10 @@ The generated site provides: - navigation across the complete guide, - full-text search, - a consistent reading layout, -- strict build validation in continuous integration. +- strict build validation in continuous integration, +- automatic publication after relevant changes reach `main`. -The site is built locally and in CI. Publishing it is a separate, later step. +Building and publishing remain separate operations with different permissions. ## Start learning diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 868da96..21f2341 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -497,6 +497,32 @@ If port 8000 is already in use, choose another address: uv run mkdocs serve --dev-addr 127.0.0.1:8001 ``` +## GitHub Pages deployment fails + +### Problem + +The `Documentation` workflow builds the site but cannot deploy it. + +### Possible causes + +- Pages is not configured to use **GitHub Actions** as its source, +- the deploy job is missing `pages: write` or `id-token: write`, +- the build job did not upload the `github-pages` artifact, +- an environment protection rule is waiting for approval, +- GitHub Pages or Actions is temporarily unavailable. + +### Fix + +Open **Settings → Pages** and confirm that **Source** is **GitHub Actions**. +Then inspect the first useful error in the failed `Deploy documentation` job. + +Do not commit `site/` or create a `gh-pages` branch to work around this workflow. +Fix the configuration in a new pull request and rerun the deployment after it +reaches `main`. + +If the workflow passed but the site still shows old content, open the deployment +URL reported by the job and confirm that the expected commit triggered the run. + ## A pre-commit hook fails or changes files ### Problem diff --git a/mkdocs.yml b/mkdocs.yml index d8ef06b..50d4ba0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,6 @@ site_name: Modern Python Project Guide site_description: A beginner-friendly guide to modern Python project tooling. +site_url: https://michalmaj.github.io/modern-python-project-guide/ repo_name: michalmaj/modern-python-project-guide repo_url: https://github.com/michalmaj/modern-python-project-guide @@ -25,6 +26,7 @@ nav: - pre-commit hooks: 13_pre_commit_hooks.md - Markdown linting with rumdl: 14_markdown_linting.md - Documentation site with MkDocs: 15_documentation_site_with_mkdocs.md + - Publishing with GitHub Pages: 16_publishing_with_github_pages.md - Project checklist: 09_checklist.md - Quickstarts: - Create a project with uv: quickstart_uv.md