Skip to content

Commit cd95dab

Browse files
authored
Merge pull request #53 from michalmaj/docs/publish-mkdocs-site
docs: publish MkDocs site with GitHub Pages
2 parents c707a98 + e925362 commit cd95dab

15 files changed

Lines changed: 309 additions & 19 deletions

‎.github/workflows/pages.yml‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Documentation
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
paths:
7+
- ".github/workflows/pages.yml"
8+
- ".python-version"
9+
- "docs/**"
10+
- "mkdocs.yml"
11+
- "pyproject.toml"
12+
- "uv.lock"
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: pages
20+
cancel-in-progress: false
21+
22+
jobs:
23+
build:
24+
name: Build documentation
25+
runs-on: ubuntu-latest
26+
permissions:
27+
contents: read
28+
pages: read
29+
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v6
33+
34+
- name: Install uv
35+
uses: astral-sh/setup-uv@v8.1.0
36+
37+
- name: Set up Python
38+
run: uv python install
39+
40+
- name: Install dependencies
41+
run: uv sync --locked --group dev
42+
43+
- name: Configure GitHub Pages
44+
uses: actions/configure-pages@v5
45+
46+
- name: Build documentation site
47+
run: uv run mkdocs build --strict
48+
49+
- name: Upload GitHub Pages artifact
50+
uses: actions/upload-pages-artifact@v5
51+
with:
52+
path: site
53+
54+
deploy:
55+
name: Deploy documentation
56+
needs: build
57+
runs-on: ubuntu-latest
58+
permissions:
59+
pages: write
60+
id-token: write
61+
environment:
62+
name: github-pages
63+
url: ${{ steps.deployment.outputs.page_url }}
64+
65+
steps:
66+
- name: Deploy to GitHub Pages
67+
id: deployment
68+
uses: actions/deploy-pages@v5

‎CONTRIBUTING.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ merging are disabled to keep that history consistent.
169169
After a pull request is merged, GitHub deletes its remote branch automatically.
170170
Delete the corresponding local branch after updating `main`.
171171

172+
When relevant documentation files change, the separate `Documentation`
173+
workflow publishes the reviewed site after the merge. This deployment is not a
174+
pull request check and does not replace the required `Quality checks` status.
175+
172176
## Documentation terminology
173177

174178
Use the official spelling of tool names: `uv`, pytest, mypy, `rumdl`, and

‎README.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Modern Python Project Guide
22

33
[![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)
4+
[![Documentation](https://github.com/michalmaj/modern-python-project-guide/actions/workflows/pages.yml/badge.svg)](https://michalmaj.github.io/modern-python-project-guide/)
45

56
A practical, beginner-friendly guide to building a clean Python project with
67
`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.
1718
- **Learn the complete workflow:** start with
1819
[Why This Guide Exists](docs/00_why_this_guide.md) and follow the main learning
1920
path below.
21+
- **Browse the published guide:** open the
22+
[documentation site](https://michalmaj.github.io/modern-python-project-guide/).
2023
- **Find a command or solve a problem:** jump to the
2124
[reference material](#reference-material).
2225

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

6671
## Reference material
6772

‎docs/01_project_structure.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ The repository currently uses this structure:
1414
modern-python-project-guide/
1515
├── .github/
1616
│ ├── workflows/
17-
│ │ └── ci.yml
17+
│ │ ├── ci.yml
18+
│ │ └── pages.yml
1819
│ └── pull_request_template.md
1920
├── docs/
2021
│ ├── 00_why_this_guide.md
@@ -107,8 +108,12 @@ Example:
107108
```text
108109
.github/pull_request_template.md
109110
.github/workflows/ci.yml
111+
.github/workflows/pages.yml
110112
```
111113

114+
The CI workflow validates pull requests and `main`. The Pages workflow publishes
115+
the documentation after relevant changes reach `main`.
116+
112117
## mkdocs.yml
113118

114119
The `mkdocs.yml` file defines the documentation site, including its navigation,

‎docs/06_github_actions.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ The workflow builds the MkDocs site with strict validation:
242242
The step validates navigation and rendering without publishing the generated
243243
site. The `site/` output directory remains an ignored local artifact.
244244

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

247252
The workflow runs tests and prints a coverage report:

‎docs/09_checklist.md‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ When the documentation set grows, a generated site can improve navigation:
204204
- [ ] generated `site/` files are ignored
205205
- [ ] strict site builds run locally and in CI
206206
- [ ] building and publishing are treated as separate operations
207+
- [ ] a dedicated deployment workflow publishes only from `main`
208+
- [ ] generated output is uploaded as an artifact instead of committed
209+
- [ ] deployment permissions are limited to the deployment job
210+
- [ ] the public site contains no secrets or private material
207211

208212
Preview and validate the site with:
209213

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

236+
## Continuous deployment
237+
238+
If the documentation is published automatically:
239+
240+
- [ ] GitHub Pages uses **GitHub Actions** as its source
241+
- [ ] the deployment workflow runs after relevant changes reach `main`
242+
- [ ] pull requests validate the site without publishing it
243+
- [ ] build and deploy jobs pass the generated site as an artifact
244+
- [ ] the deployment uses the `github-pages` environment
245+
- [ ] the published site is checked after deployment
246+
232247
CI helps protect the main branch from broken changes.
233248

234249
## Git workflow
@@ -355,5 +370,5 @@ Let the project grow gradually.
355370

356371
## Continue
357372

358-
- [Previous: Documentation Site with MkDocs](15_documentation_site_with_mkdocs.md)
373+
- [Previous: Publishing with GitHub Pages](16_publishing_with_github_pages.md)
359374
- [Back to documentation home](index.md)

‎docs/15_documentation_site_with_mkdocs.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,14 @@ The documentation checks have separate responsibilities:
101101

102102
No single tool replaces the others.
103103

104-
## Build is not deployment
104+
## Build and deployment are separate
105105

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

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

112113
## Rule of thumb
113114

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

120121
- [Previous: Markdown Linting with rumdl](14_markdown_linting.md)
121-
- [Next: Project Checklist](09_checklist.md)
122+
- [Next: Publishing with GitHub Pages](16_publishing_with_github_pages.md)
122123
- [Back to documentation home](index.md)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Publishing with GitHub Pages
2+
3+
A strict MkDocs build proves that the documentation can be generated. GitHub
4+
Pages makes that generated site available to readers on the web.
5+
6+
This project publishes the site at:
7+
8+
<https://michalmaj.github.io/modern-python-project-guide/>
9+
10+
## Build and deployment remain separate
11+
12+
The repository has two workflows with different responsibilities:
13+
14+
- `.github/workflows/ci.yml` validates every pull request and push to `main`,
15+
- `.github/workflows/pages.yml` publishes documentation after relevant changes
16+
reach `main`.
17+
18+
A pull request therefore cannot update the public site. It must first pass the
19+
normal review and `Quality checks` requirement. The merge commit then starts the
20+
documentation workflow.
21+
22+
## One-time repository setting
23+
24+
The repository owner must enable GitHub Pages once:
25+
26+
1. Open the repository **Settings**.
27+
2. Select **Pages** under **Code, planning, and automation**.
28+
3. Under **Build and deployment**, set **Source** to **GitHub Actions**.
29+
30+
The workflow does not publish from a `gh-pages` branch and does not commit the
31+
generated `site/` directory.
32+
33+
## When deployment runs
34+
35+
The documentation workflow runs when a push to `main` changes its own workflow,
36+
the Python version, documentation sources, MkDocs configuration, or dependency
37+
files. It can also be started manually from the **Actions** tab.
38+
39+
The path filter avoids redeploying an unchanged site after unrelated source-code
40+
changes. Manual dispatch remains available for recovery or verification.
41+
42+
## Build job
43+
44+
The `build` job recreates the site from a clean checkout:
45+
46+
1. check out the repository,
47+
2. install `uv` and the configured Python version,
48+
3. install locked development dependencies,
49+
4. configure GitHub Pages,
50+
5. run `uv run mkdocs build --strict`,
51+
6. upload `site/` as a GitHub Pages artifact.
52+
53+
The artifact is the boundary between building and deploying. It contains the
54+
generated static site, but it is not committed to the repository.
55+
56+
## Deploy job
57+
58+
The `deploy` job waits for the build job. It deploys the uploaded artifact to
59+
the `github-pages` environment and reports the resulting public URL.
60+
61+
The workflow grants only the permissions it needs:
62+
63+
- `contents: read` reads repository files,
64+
- `pages: write` creates the Pages deployment,
65+
- `id-token: write` lets GitHub verify the deployment with OpenID Connect.
66+
67+
The write permissions belong only to the deploy job. The normal CI workflow
68+
does not receive them.
69+
70+
## Why use an environment?
71+
72+
GitHub Pages deployments use the `github-pages` environment. It records
73+
deployment history and can enforce protection rules.
74+
75+
The workflow also uses a `pages` concurrency group. A running production
76+
deployment is allowed to finish instead of being cancelled by a newer run.
77+
78+
## Verify a deployment
79+
80+
After merging a documentation change:
81+
82+
1. open the repository **Actions** tab,
83+
2. select the **Documentation** workflow,
84+
3. confirm that **Build documentation** and **Deploy documentation** passed,
85+
4. open the deployment URL shown by the deploy job,
86+
5. verify the changed page and navigation.
87+
88+
The existing `Quality checks` status remains the branch-protection requirement.
89+
Deployment happens after merge, so a deployment failure should be fixed with a
90+
new pull request rather than by weakening that requirement.
91+
92+
## Public output and secrets
93+
94+
Everything in the generated site is public. Documentation sources and build
95+
configuration must not contain credentials, private notes, or other sensitive
96+
information.
97+
98+
This workflow needs no repository secrets. GitHub supplies a short-lived token
99+
with the declared permissions.
100+
101+
## Custom domains are separate
102+
103+
This project uses the default `github.io` address. A custom domain would require
104+
additional DNS and repository settings and is intentionally outside this setup.
105+
106+
## Rule of thumb
107+
108+
Validate on pull requests. Publish only from the protected default branch.
109+
110+
Keep generated files out of Git and deploy a reproducible artifact instead.
111+
112+
## Continue
113+
114+
- [Previous: Documentation Site with MkDocs](15_documentation_site_with_mkdocs.md)
115+
- [Next: Project Checklist](09_checklist.md)
116+
- [Back to documentation home](index.md)

‎docs/ROADMAP.md‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ These parts are already included in the repository.
140140
- [x] Keep Markdown linting separate from link checks and human review
141141
- [x] Add an MkDocs site with explicit navigation and strict CI builds
142142
- [x] Keep documentation sources readable without the generated site
143+
- [x] Publish the documentation site with GitHub Pages
144+
- [x] Keep validation and deployment in separate workflows
143145

144146
## Next
145147

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

170172
- [ ] Explain publishing to PyPI
171173

172-
### Documentation site
173-
174-
- [ ] Decide whether to publish the MkDocs site with GitHub Pages
175-
176174
### Release automation
177175

178176
- [ ] Explain versioning
@@ -192,7 +190,7 @@ These topics were deliberately excluded from the original foundation:
192190
- Docker,
193191
- publishing to PyPI,
194192
- release automation,
195-
- documentation site generation,
193+
- documentation site generation and deployment,
196194
- pre-commit hooks,
197195
- coverage gates,
198196
- complex multi-job CI,

‎docs/common_questions.md‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,22 @@ They point readers toward the same material, but they appear in different
389389
contexts. Keeping the site landing page inside `docs/` also follows MkDocs'
390390
normal source layout.
391391

392-
## Why does CI build the site without publishing it?
392+
## Why does pull request CI build the site without publishing it?
393393

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

397397
Publishing requires a separate deployment workflow, permissions, and GitHub
398-
Pages settings. Those decisions should be reviewed independently after the
399-
local site has proved useful.
398+
Pages settings. In this repository, that workflow runs only after relevant
399+
changes reach `main`, so a pull request cannot update the public site.
400+
401+
## Where is the documentation site published?
402+
403+
The site is available at
404+
<https://michalmaj.github.io/modern-python-project-guide/>.
405+
406+
The `Documentation` workflow builds it from the same Markdown sources and
407+
deploys a generated artifact. The generated `site/` directory is not committed.
400408

401409
## Rule of thumb
402410

0 commit comments

Comments
 (0)