Skip to content

Commit 2029050

Browse files
committed
✨ feat: add support for GitHub Actions
1 parent 4135758 commit 2029050

File tree

5 files changed

+244
-26
lines changed

5 files changed

+244
-26
lines changed

README.md

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ A modern, batteries‑included [Copier](https://github.com/copier-org/copier) te
1313
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
1414
[![GitHub](https://img.shields.io/github/license/bassemkaroui/python-template-uv)](https://github.com/bassemkaroui/python-template-uv/blob/main/LICENSE)
1515

16-
1716
</div>
1817

1918
## 🚀 Features
@@ -26,39 +25,55 @@ A modern, batteries‑included [Copier](https://github.com/copier-org/copier) te
2625
Simply run tasks with `make <task>` (e.g. `make check`, `make docs`).
2726

2827
- **Quality & standards**
28+
2929
- **Formatting** and **Linting**: [Ruff](https://github.com/astral-sh/ruff)`make format` & `make check-quality`
3030
- **Type checking**: [Mypy](https://github.com/python/mypy)`make check-types`
3131
- **Pre-commit hooks**: [pre-commit](https://pre-commit.com/)
3232

3333
- **Testing & coverage**
34+
3435
- [**pytest**](https://github.com/pytest-dev/pytest)`make test`
3536
- [**Coverage**](https://github.com/nedbat/coveragepy) (text, HTML, XML) ➜ `make coverage`
3637
- Compatibility testing for multiple versions of Python with [**Tox**](https://github.com/tox-dev/tox) and its plugin [tox-uv](https://github.com/tox-dev/tox-uv)`make tox`
3738

3839
- **Documentation**
40+
3941
- [**MkDocs**](https://github.com/mkdocs/mkdocs) with [mkdocs-material](https://github.com/squidfunk/mkdocs-material) theme
4042
- Live server: `make docs` (serves on localhost:8080)
4143
- Deploy to GitHub Pages: `make docs-deploy`
4244

4345
- **Release & changelog**
46+
4447
- [Conventional Commits](https://www.conventionalcommits.org/) + [Commitizen](https://github.com/commitizen-tools/commitizen) + [gitmoji](https://github.com/ljnsn/cz-conventional-gitmoji)
4548
- Automated `CHANGELOG.md` updates
4649
- Release new versions ➜ `make release`
4750

48-
4951
- **Docker & Docker Compose**
52+
5053
- Generate `Dockerfile` + `compose.yml` for local development and deployment (GPU support)
5154
- Docker targets: `make docker-build`, `make docker-start`, `make docker-stop`
5255

5356
- **Optional tooling**
57+
5458
- Typer CLI scaffold
5559
- Strict typing
5660
- Run tests with parallel execution via pytest-xdist
5761
- Preconfigured dependency categories (ML, data, web, etc.)
5862

59-
- **Future CI support**:
60-
CI workflows are scaffolded for upcoming releases.
63+
- **CI/CD Workflows**
6164

65+
This template includes GitHub Actions workflows for continuous integration, testing, and release automation:
66+
67+
- **PR Commenting** (`pr-thank-you.yaml`): Posts a fun GIPHY comment on new pull requests using [`docker-action-pr-giphy-comment`](https://github.com/bassemkaroui/docker-action-pr-giphy-comment)
68+
69+
- **CI/CD Pipeline** (`main.yaml.jinja`):
70+
- **Checks**: Linting (Ruff), type checking (Mypy), documentation build.
71+
- **Tests**: Runs `pytest` across supported Python versions using a matrix strategy.
72+
- **Releases**: Automatically publishes releases when a Git tag is pushed.
73+
- **Docs Deployment**: Deploys MkDocs documentation to GitHub Pages.
74+
- **Package Publishing** (optional): Publishes the package to PyPI if `publish_to_pypi` is enabled and `PYPI_TOKEN` is set.
75+
76+
These workflows are generated into `.github/workflows/` in the scaffolded project. You can customize them further as needed.
6277

6378
## 🛠 Prerequisites
6479

@@ -67,7 +82,6 @@ A modern, batteries‑included [Copier](https://github.com/copier-org/copier) te
6782
- **copier-templates-extensions** ≥ 0.3.1
6883
- **uv** (if not installed check [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/))
6984

70-
7185
## 🎉 Quickstart
7286

7387
```bash
@@ -101,6 +115,7 @@ make check # runs all checks: lint, types, docs build, API, etc.
101115
```
102116

103117
**Stay up to date**
118+
104119
```bash
105120
cd /path/to/my-project
106121

@@ -110,7 +125,6 @@ uvx copier update --trust --exclude src/ --exclude tests/ .
110125
> [!WARNING]
111126
> To be able to [update your project](https://copier.readthedocs.io/en/stable/updating/), do not delete or manually modify the generated `.copier-answers.yml` file.
112127
113-
114128
## 📋 Available Duties
115129

116130
All tasks are defined in `duties.py` and exposed through `make`. Common duties include:
@@ -143,33 +157,31 @@ tox Run tests across multiple Python versions.
143157

144158
For the full list and details, see [duties.py](https://github.com/bassemkaroui/python-template-uv/blob/main/template/duties.py.jinja).
145159

146-
147160
## 🔧 Template Variables
148161

149162
When running `copier`, you’ll be prompted for:
150163

151-
| Variable | Description | Default |
152-
| -------------------------- | ---------------------------------------------------------------- | ------------------ |
153-
| `project_name` | Your project’s **name** (lowercase, letters/digits/dashes) | ** |
154-
| `project_description` | A short summary of what your project does | ** |
155-
| `author_fullname` | Your full name | from `git` |
156-
| `author_email` | Your email address | from `git` |
157-
| `repository_provider` | Where you host your repo (`github` or `other`) | `github` |
158-
| `homepage` | Project homepage URL | `https://<user>.github.io/<proj>` |
159-
| `python_version` | Default Python interpreter for development | `3.12` |
160-
| `min_python_version` | Minimum supported Python version | `3.10` |
161-
| `with_typer_cli` | Include a Typer CLI scaffold? | `false` |
162-
| `with_strict_typing` | Enable strict typing enforcement? | `false` |
163-
| `tox` | Include Tox configuration? | `true` |
164-
| `coverage_threshold` | Minimum test coverage % | `100` |
165-
| `with_conventional_commits`| Enforce Conventional Commits? | `true` |
166-
| `cz_gitmoji` | Include emojis in commit messages? | `true` |
167-
| `dockerfile` | Generate Dockerfile and Compose file? | `true` |
168-
| `gpus` | Enable GPU support in Docker builds? | `false` |
164+
| Variable | Description | Default |
165+
| --------------------------- | ---------------------------------------------------------- | --------------------------------- |
166+
| `project_name` | Your project’s **name** (lowercase, letters/digits/dashes) | __ |
167+
| `project_description` | A short summary of what your project does | __ |
168+
| `author_fullname` | Your full name | from `git` |
169+
| `author_email` | Your email address | from `git` |
170+
| `repository_provider` | Where you host your repo (`github` or `other`) | `github` |
171+
| `homepage` | Project homepage URL | `https://<user>.github.io/<proj>` |
172+
| `python_version` | Default Python interpreter for development | `3.12` |
173+
| `min_python_version` | Minimum supported Python version | `3.10` |
174+
| `with_typer_cli` | Include a Typer CLI scaffold? | `false` |
175+
| `with_strict_typing` | Enable strict typing enforcement? | `false` |
176+
| `tox` | Include Tox configuration? | `true` |
177+
| `coverage_threshold` | Minimum test coverage % | `100` |
178+
| `with_conventional_commits` | Enforce Conventional Commits? | `true` |
179+
| `cz_gitmoji` | Include emojis in commit messages? | `true` |
180+
| `dockerfile` | Generate Dockerfile and Compose file? | `true` |
181+
| `gpus` | Enable GPU support in Docker builds? | `false` |
169182

170183
> See the full list in [copier.yaml](https://github.com/bassemkaroui/python-template-uv/blob/main/copier.yaml).
171184
172-
173185
## 📄 License
174186

175187
This project is released under the **MIT License**. See [LICENSE](https://github.com/bassemkaroui/python-template-uv/blob/main/LICENSE) for details.

template/README.md.jinja

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
{%- endif %}
1313
{%- if repository_provider == 'github' %}
1414
[![Release](https://img.shields.io/github/v/release/{{ author_github_handle }}/{{ project_name }})](https://github.com/{{ author_github_handle }}/{{ project_name }}/releases)
15+
[![CI/CD Pipeline](https://github.com/{{ author_github_handle }}/{{ project_name }}/actions/workflows/main.yaml/badge.svg)](https://github.com/{{ author_github_handle }}/{{ project_name }}/actions/workflows/main.yaml)
1516
[![Commit activity](https://img.shields.io/github/commit-activity/m/{{ author_github_handle }}/{{ project_name }})](https://github.com/{{ author_github_handle }}/{{ project_name }}/commits)
1617
[![GitHub](https://img.shields.io/github/license/{{ author_github_handle }}/{{ project_name }})](https://github.com/{{ author_github_handle }}/{{ project_name }}/blob/main/LICENSE)
1718
{%- endif %}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: 'Setup UV & Python'
2+
description: 'Checks out the repo, sets up `uv`, and installs the right Python version (supports file or literal).'
3+
inputs:
4+
python-version:
5+
description: 'Literal Python version (e.g. "3.12")'
6+
required: false
7+
python-version-file:
8+
description: 'Path to a .python-version file'
9+
required: false
10+
11+
runs:
12+
using: composite
13+
steps:
14+
- name: Setup uv
15+
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6
16+
17+
- name: Setup Python
18+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
19+
with:
20+
# one of these two
21+
python-version: ${{ inputs.python-version }}
22+
python-version-file: ${{ inputs.python-version-file }}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
name: CI
2+
3+
concurrency:
4+
group: {% raw %}${{ github.workflow }}-${{ github.ref }}{% endraw %}
5+
cancel-in-progress: true
6+
7+
on:
8+
push:
9+
branches:
10+
- main
11+
tags:
12+
- "*"
13+
pull_request:
14+
types: [opened, synchronize, reopened, ready_for_review]
15+
workflow_dispatch:
16+
17+
jobs:
18+
checks:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
23+
with:
24+
fetch-depth: 0
25+
fetch-tags: true
26+
27+
- name: Setup env
28+
uses: ./.github/actions/setup-env
29+
with:
30+
python-version-file: ".python-version"
31+
32+
- name: Check the code quality with Ruff
33+
run: make check-quality
34+
35+
- name: Check typing
36+
run: make check-types
37+
38+
- name: Check if the documentation builds correctly
39+
run: make check-docs
40+
41+
tests:
42+
runs-on: ubuntu-latest
43+
strategy:
44+
matrix:
45+
python-version:
46+
{%- set start = min_python_version.split('.')[-1] | int %}
47+
{%- set majors = range(start, 14) %}
48+
{%- for minor in majors %}
49+
- "3.{{ minor }}"
50+
{%- endfor %}
51+
fail-fast: false
52+
steps:
53+
- name: Checkout repository
54+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
55+
with:
56+
fetch-depth: 0
57+
fetch-tags: true
58+
59+
- name: Setup env
60+
uses: ./.github/actions/setup-env
61+
with:
62+
python-version: {% raw %}${{ matrix.python-version }}{% endraw %}
63+
64+
- name: Run tests
65+
run: make test
66+
67+
release:
68+
runs-on: ubuntu-latest
69+
if: |
70+
github.event_name == 'push' &&
71+
startsWith(github.ref, 'refs/tags/')
72+
needs:
73+
- checks
74+
- tests
75+
permissions:
76+
contents: write
77+
steps:
78+
- name: Checkout repository
79+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
80+
with:
81+
fetch-depth: 0
82+
fetch-tags: true
83+
84+
- name: Setup env
85+
uses: ./.github/actions/setup-env
86+
with:
87+
python-version-file: ".python-version"
88+
89+
- name: Prepare release notes
90+
run: {% raw %}uvx --from commitizen --with cz-conventional-gitmoji cz changelog ${{ github.ref_name }} --file-name release-notes.md && echo ${{ github.ref }}{% endraw %}
91+
92+
- name: Create release
93+
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2
94+
with:
95+
body_path: release-notes.md
96+
prerelease: {% raw %}${{ contains(github.ref_name, 'rc') || contains(github.ref_name, 'b') || contains(github.ref_name, 'a') }}{% endraw %}
97+
98+
deploy-docs:
99+
if: |
100+
github.event_name == 'workflow_dispatch' ||
101+
(github.event_name == 'push' &&
102+
startsWith(github.ref, 'refs/tags/'))
103+
runs-on: ubuntu-latest
104+
needs:
105+
- checks
106+
- tests
107+
permissions:
108+
contents: write
109+
pages: write
110+
id-token: write
111+
steps:
112+
- name: Checkout repository
113+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
114+
with:
115+
fetch-depth: 0
116+
fetch-tags: true
117+
118+
- name: Setup env
119+
uses: ./.github/actions/setup-env
120+
with:
121+
python-version-file: ".python-version"
122+
123+
- name: Build docs
124+
run: uv run mkdocs build
125+
126+
- name: Deploy to GitHub Pages
127+
uses: peaceiris/actions-gh-pages@e9c66a37f080288a11235e32cbe2dc5fb3a679cc # v4
128+
with:
129+
github_token: {% raw %}${{ secrets.GITHUB_TOKEN }}{% endraw %}
130+
publish_dir: ./site
131+
{%- if publish_to_pypi %}
132+
133+
publish-package:
134+
if: |
135+
github.event_name == 'workflow_dispatch' ||
136+
(github.event_name == 'push' &&
137+
startsWith(github.ref, 'refs/tags/'))
138+
runs-on: ubuntu-latest
139+
needs:
140+
- checks
141+
- tests
142+
steps:
143+
- name: Checkout repository
144+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
145+
with:
146+
fetch-depth: 0
147+
fetch-tags: true
148+
149+
- name: Setup env
150+
uses: ./.github/actions/setup-env
151+
with:
152+
python-version-file: ".python-version"
153+
154+
- name: Build package
155+
run: uv build
156+
157+
- name: Publish package
158+
if: secrets.PYPI_TOKEN != ''
159+
env:
160+
UV_PUBLISH_TOKEN: {% raw %}${{ secrets.PYPI_TOKEN }}{% endraw %}
161+
run: uv publish
162+
{%- endif %}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
on:
2+
pull_request:
3+
types:
4+
- opened
5+
6+
jobs:
7+
pr-action:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
steps:
13+
- name: Post PR Comment
14+
id: giphy
15+
uses: bassemkaroui/docker-action-pr-giphy-comment@v1
16+
with:
17+
github-token: ${{ secrets.GITHUB_TOKEN }}
18+
giphy-api-key: ${{ secrets.GIPHY_API_KEY }}
19+
20+
- name: Log Comment URL
21+
run: echo "URL - ${{ steps.giphy.outputs.pr-comment-url }}"

0 commit comments

Comments
 (0)