-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.md.jinja
More file actions
278 lines (198 loc) · 7.46 KB
/
README.md.jinja
File metadata and controls
278 lines (198 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# {{ project_name }}
{{ project_description }}
---
## Table of Contents
- [Features](#features)
- [Prerequisites](#prerequisites)
- [Getting Started](#getting-started)
- [Project Structure](#project-structure)
- [Development Workflow](#development-workflow)
- [Running Tests](#running-tests)
- [Code Quality](#code-quality)
- [Documentation](#documentation)
- [Docker](#docker)
- [CI/CD](#cicd)
- [Publishing to PyPI](#publishing-to-pypi)
- [Contributing](#contributing)
---
## Features
| Area | Tooling |
|---|---|
| Package manager | [uv](https://github.com/astral-sh/uv) — fast, lock-file-based |
| Linting & formatting | [Ruff](https://github.com/astral-sh/ruff) |
| Type checking | [MyPy](https://mypy-lang.org/) (strict mode) |
| Testing | [pytest](https://pytest.org) + [pytest-asyncio](https://pytest-asyncio.readthedocs.io) + [pytest-cov](https://pytest-cov.readthedocs.io) |
| Security scanning | [Bandit](https://bandit.readthedocs.io) |
| Documentation | [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) with auto-generated API reference |
| Changelog | [towncrier](https://towncrier.readthedocs.io) |
| Build system | [Hatchling](https://hatch.pypa.io) |
| Containerization | Multi-stage Docker build (validate → production) |
| CI/CD | GitHub Actions (docs, Docker image, PyPI publish) |
| Dev environment | VS Code Dev Container with `act` for local workflow testing |
---
## Prerequisites
**For Option A (Dev Container):**
- [Docker](https://docs.docker.com/get-docker/) (Desktop or Engine)
- [VS Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
**For Option B (local):**
- Python 3.12 or newer
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
---
## Getting Started
### Option A — Dev Container (recommended)
1. **Clone the repository:**
```bash
git clone {{ repo_url }}.git
cd {{ module_name }}
```
2. **Open in VS Code and reopen in container:**
```
Ctrl+Shift+P → Dev Containers: Reopen in Container
```
VS Code will build the container image and run the post-creation script, which installs all dependencies automatically via `uv sync --locked`.
3. **Verify the setup:**
```bash
make help
```
### Option B — Local Setup
1. **Clone the repository:**
```bash
git clone {{ repo_url }}.git
cd {{ module_name }}
```
2. **Install uv** (if not already installed):
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
3. **Install dependencies:**
```bash
make setup
```
4. **Verify the setup:**
```bash
make help
```
---
## Project Structure
```
{{ module_name }}/
├── .changelog/ # Pending changelog entries (towncrier)
├── .devcontainer/ # VS Code dev container definition
├── .github/
│ ├── dependabot.yml # Automated dependency updates (weekly)
│ └── workflows/
│ ├── docs.yml # Build and deploy documentation to GitHub Pages
│ ├── image.yml # Build and push Docker image to registry
│ └── pypi.yml # Build and publish package to PyPI
├── docker/
│ ├── Dockerfile # Multi-stage build: builder → validate → production
│ └── entrypoint.sh # Container entrypoint
├── docs/ # MkDocs source
├── examples/ # Usage examples (add yours here)
├── src/
│ └── {{ module_name }}/ # Package source code
│ ├── __init__.py
│ └── __version__.py
├── tests/ # pytest test suite
├── CHANGELOG.md # Auto-generated changelog
├── CONTRIBUTING.md # Contribution guidelines
├── Makefile # Common development tasks
├── mkdocs.yml # Documentation configuration
├── pyproject.toml # Project metadata, dependencies, and tool config
└── uv.lock # Locked dependency versions (do not edit manually)
```
---
## Development Workflow
All common tasks are available through `make`. Run `make help` to see the full list.
| Command | Description |
|---|---|
| `make setup` | Install all dependencies (first-time setup) |
| `make sync` | Re-sync dependencies after editing `pyproject.toml` |
| `make lock` | Update `uv.lock` after adding or removing dependencies |
| `make format` | Auto-format code with Ruff |
| `make lint` | Run Ruff (linter) and MyPy (type checker) |
| `make test` | Run the test suite with coverage |
| `make clean` | Remove build artefacts and caches |
| `make all` | Full local CI pipeline: clean → install → lint → test |
### Adding a dependency
```bash
uv add <package> # runtime dependency
uv add --dev <package> # development-only dependency
make lock # update uv.lock
```
---
## Running Tests
```bash
make test
```
This runs `pytest` with branch coverage enabled. A minimum of **75%** coverage is required. To view a detailed HTML report:
```bash
uv run pytest --cov=src --cov-report=html
open htmlcov/index.html
```
Tests requiring async support use `pytest-asyncio`. Mark async test functions with `@pytest.mark.asyncio`.
---
## Code Quality
### Format
```bash
make format
```
### Lint
```bash
make lint
```
Runs two checks in sequence:
1. **Ruff** — covers flake8, isort, pyupgrade, bugbear, and more.
2. **MyPy** — strict type checking across `src/{{ module_name }}/` and `tests/`.
### Security scan
```bash
uv run bandit -r src/
```
---
## Documentation
### Serve locally
```bash
uv run --group docs mkdocs serve
```
Open [http://localhost:8000](http://localhost:8000) in your browser.
### Build
```bash
uv run --group docs mkdocs build
```
### Deploy
Documentation is deployed to GitHub Pages automatically by the `docs.yml` workflow on every push to `main`.
---
## Docker
| Stage | Purpose |
|---|---|
| `builder-base` | Installs locked dependencies (no dev extras) |
| `validate` | Runs format check, Ruff, MyPy, pytest, and Bandit |
| `production` | Minimal runtime image; runs as a non-root user (UID 1001) |
```bash
# Run only the validation stage
docker build --target validate -f docker/Dockerfile .
# Build the final production image
docker build -f docker/Dockerfile -t {{ module_name }}:local .
# Run
docker run --rm {{ module_name }}:local
```
---
## CI/CD
| Workflow | Trigger | What it does |
|---|---|---|
| `docs.yml` | Push to `main` (docs/src/mkdocs) or manual | Builds and publishes documentation to GitHub Pages |
| `image.yml` | Push to `main`/`development` (docker/src/tests) or manual | Validates and builds the Docker image, pushes to registry |
| `pypi.yml` | Push to `main` or manual | Builds and publishes the package to PyPI |
---
## Publishing to PyPI
Releases are published automatically via GitHub Actions using **Trusted Publishing** (OIDC) — no long-lived API tokens required.
1. Go to your repository → **Settings** → **Environments** → create an environment named **`pypi`**.
2. On PyPI, add a trusted publisher under **Manage** → **Publishing** with:
- **Repository owner**: `{{ repo_url | replace('https://github.com/', '') | regex_replace('/[^/]+$', '') }}`
- **Repository name**: the name of this repo
- **Workflow filename**: `pypi.yml`
- **Environment name**: `pypi`
3. To release: update the version in `pyproject.toml`, commit, and push to `main` (or create a GitHub Release tag).
---
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full contribution guide.