Skip to content

Commit 0bc43e2

Browse files
authored
initial implementation (#1)
1 parent 056e8b1 commit 0bc43e2

File tree

17 files changed

+1923
-0
lines changed

17 files changed

+1923
-0
lines changed

.github/actions/uv_setup/action.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# TODO: https://docs.astral.sh/uv/guides/integration/github/#caching
2+
3+
name: uv-install
4+
description: Set up Python and uv
5+
6+
inputs:
7+
python-version:
8+
description: Python version, supporting MAJOR.MINOR only
9+
required: true
10+
11+
env:
12+
UV_VERSION: "0.5.25"
13+
14+
runs:
15+
using: composite
16+
steps:
17+
- name: Install uv and set the python version
18+
uses: astral-sh/setup-uv@v5
19+
with:
20+
version: ${{ env.UV_VERSION }}
21+
python-version: ${{ inputs.python-version }}

.github/workflows/_lint.yml

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: lint
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
working-directory:
7+
required: true
8+
type: string
9+
description: "From which folder this pipeline executes"
10+
python-version:
11+
required: true
12+
type: string
13+
description: "Python version to use"
14+
15+
env:
16+
WORKDIR: ${{ inputs.working-directory == '' && '.' || inputs.working-directory }}
17+
18+
# This env var allows us to get inline annotations when ruff has complaints.
19+
RUFF_OUTPUT_FORMAT: github
20+
21+
UV_FROZEN: "true"
22+
23+
jobs:
24+
build:
25+
name: "make lint #${{ inputs.python-version }}"
26+
runs-on: ubuntu-latest
27+
timeout-minutes: 20
28+
steps:
29+
- uses: actions/checkout@v4
30+
31+
- name: Set up Python ${{ inputs.python-version }} + uv
32+
uses: "./.github/actions/uv_setup"
33+
with:
34+
python-version: ${{ inputs.python-version }}
35+
36+
- name: Install dependencies
37+
working-directory: ${{ inputs.working-directory }}
38+
run: |
39+
uv sync --group test
40+
41+
- name: Analysing the code with our lint
42+
working-directory: ${{ inputs.working-directory }}
43+
run: |
44+
make lint

.github/workflows/_test.yml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: test
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
working-directory:
7+
required: true
8+
type: string
9+
description: "From which folder this pipeline executes"
10+
python-version:
11+
required: true
12+
type: string
13+
description: "Python version to use"
14+
15+
env:
16+
UV_FROZEN: "true"
17+
UV_NO_SYNC: "true"
18+
19+
jobs:
20+
build:
21+
defaults:
22+
run:
23+
working-directory: ${{ inputs.working-directory }}
24+
runs-on: ubuntu-latest
25+
timeout-minutes: 20
26+
name: "make test #${{ inputs.python-version }}"
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- name: Set up Python ${{ inputs.python-version }} + uv
31+
uses: "./.github/actions/uv_setup"
32+
id: setup-python
33+
with:
34+
python-version: ${{ inputs.python-version }}
35+
- name: Install dependencies
36+
shell: bash
37+
run: uv sync --group test
38+
39+
- name: Run core tests
40+
shell: bash
41+
run: |
42+
make test

.github/workflows/ci.yml

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
name: Run CI Tests
3+
4+
on:
5+
push:
6+
branches: [ main ]
7+
pull_request:
8+
workflow_dispatch: # Allows to trigger the workflow manually in GitHub UI
9+
10+
# If another push to the same PR or branch happens while this workflow is still running,
11+
# cancel the earlier run in favor of the next run.
12+
#
13+
# There's no point in testing an outdated version of the code. GitHub only allows
14+
# a limited number of job runners to be active at the same time, so it's better to cancel
15+
# pointless jobs early so that more useful jobs can run sooner.
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
jobs:
21+
lint:
22+
strategy:
23+
matrix:
24+
# Only lint on the min and max supported Python versions.
25+
# It's extremely unlikely that there's a lint issue on any version in between
26+
# that doesn't show up on the min or max versions.
27+
#
28+
# GitHub rate-limits how many jobs can be running at any one time.
29+
# Starting new jobs is also relatively slow,
30+
# so linting on fewer versions makes CI faster.
31+
python-version:
32+
- "3.12"
33+
uses:
34+
./.github/workflows/_lint.yml
35+
with:
36+
working-directory: .
37+
python-version: ${{ matrix.python-version }}
38+
secrets: inherit
39+
test:
40+
strategy:
41+
matrix:
42+
# Only lint on the min and max supported Python versions.
43+
# It's extremely unlikely that there's a lint issue on any version in between
44+
# that doesn't show up on the min or max versions.
45+
#
46+
# GitHub rate-limits how many jobs can be running at any one time.
47+
# Starting new jobs is also relatively slow,
48+
# so linting on fewer versions makes CI faster.
49+
python-version:
50+
- "3.10"
51+
- "3.12"
52+
uses:
53+
./.github/workflows/_test.yml
54+
with:
55+
working-directory: .
56+
python-version: ${{ matrix.python-version }}
57+
secrets: inherit
58+

.github/workflows/release.yml

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: release
2+
run-name: Release ${{ inputs.working-directory }} by @${{ github.actor }}
3+
on:
4+
workflow_call:
5+
inputs:
6+
working-directory:
7+
required: true
8+
type: string
9+
description: "From which folder this pipeline executes"
10+
workflow_dispatch:
11+
inputs:
12+
working-directory:
13+
description: "From which folder this pipeline executes"
14+
default: "."
15+
dangerous-nonmain-release:
16+
required: false
17+
type: boolean
18+
default: false
19+
description: "Release from a non-main branch (danger!)"
20+
21+
env:
22+
PYTHON_VERSION: "3.11"
23+
UV_FROZEN: "true"
24+
UV_NO_SYNC: "true"
25+
26+
jobs:
27+
build:
28+
if: github.ref == 'refs/heads/main' || inputs.dangerous-nonmain-release
29+
environment: Scheduled testing
30+
runs-on: ubuntu-latest
31+
32+
outputs:
33+
pkg-name: ${{ steps.check-version.outputs.pkg-name }}
34+
version: ${{ steps.check-version.outputs.version }}
35+
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- name: Set up Python + uv
40+
uses: "./.github/actions/uv_setup"
41+
with:
42+
python-version: ${{ env.PYTHON_VERSION }}
43+
44+
# We want to keep this build stage *separate* from the release stage,
45+
# so that there's no sharing of permissions between them.
46+
# The release stage has trusted publishing and GitHub repo contents write access,
47+
# and we want to keep the scope of that access limited just to the release job.
48+
# Otherwise, a malicious `build` step (e.g. via a compromised dependency)
49+
# could get access to our GitHub or PyPI credentials.
50+
#
51+
# Per the trusted publishing GitHub Action:
52+
# > It is strongly advised to separate jobs for building [...]
53+
# > from the publish job.
54+
# https://github.com/pypa/gh-action-pypi-publish#non-goals
55+
- name: Build project for distribution
56+
run: uv build
57+
- name: Upload build
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: dist
61+
path: ${{ inputs.working-directory }}/dist/
62+
63+
- name: Check Version
64+
id: check-version
65+
shell: python
66+
working-directory: ${{ inputs.working-directory }}
67+
run: |
68+
import os
69+
import tomllib
70+
with open("pyproject.toml", "rb") as f:
71+
data = tomllib.load(f)
72+
pkg_name = data["project"]["name"]
73+
version = data["project"]["version"]
74+
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
75+
f.write(f"pkg-name={pkg_name}\n")
76+
f.write(f"version={version}\n")
77+
publish:
78+
needs:
79+
- build
80+
runs-on: ubuntu-latest
81+
permissions:
82+
# This permission is used for trusted publishing:
83+
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
84+
#
85+
# Trusted publishing has to also be configured on PyPI for each package:
86+
# https://docs.pypi.org/trusted-publishers/adding-a-publisher/
87+
id-token: write
88+
89+
defaults:
90+
run:
91+
working-directory: ${{ inputs.working-directory }}
92+
93+
steps:
94+
- uses: actions/checkout@v4
95+
96+
- name: Set up Python + uv
97+
uses: "./.github/actions/uv_setup"
98+
with:
99+
python-version: ${{ env.PYTHON_VERSION }}
100+
101+
- uses: actions/download-artifact@v4
102+
with:
103+
name: dist
104+
path: ${{ inputs.working-directory }}/dist/
105+
106+
- name: Publish package distributions to PyPI
107+
uses: pypa/gh-action-pypi-publish@release/v1
108+
with:
109+
packages-dir: ${{ inputs.working-directory }}/dist/
110+
verbose: true
111+
print-hash: true
112+
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
113+
attestations: false
114+
115+
mark-release:
116+
needs:
117+
- build
118+
- publish
119+
runs-on: ubuntu-latest
120+
permissions:
121+
# This permission is needed by `ncipollo/release-action` to
122+
# create the GitHub release.
123+
contents: write
124+
125+
defaults:
126+
run:
127+
working-directory: ${{ inputs.working-directory }}
128+
129+
steps:
130+
- uses: actions/checkout@v4
131+
132+
- name: Set up Python + uv
133+
uses: "./.github/actions/uv_setup"
134+
with:
135+
python-version: ${{ env.PYTHON_VERSION }}
136+
137+
- uses: actions/download-artifact@v4
138+
with:
139+
name: dist
140+
path: ${{ inputs.working-directory }}/dist/
141+
142+
- name: Create Tag
143+
uses: ncipollo/release-action@v1
144+
with:
145+
artifacts: "dist/*"
146+
token: ${{ secrets.GITHUB_TOKEN }}
147+
generateReleaseNotes: true
148+
tag: ${{needs.build.outputs.pkg-name}}==${{ needs.build.outputs.version }}
149+
body: ${{ needs.release-notes.outputs.release-body }}
150+
commit: main
151+
makeLatest: true

.gitignore

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Pyenv
2+
.python-version
3+
4+
# Byte-compiled / optimized / DLL files
5+
__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
9+
# C extensions
10+
*.so
11+
12+
# Distribution / packaging
13+
.Python
14+
build/
15+
develop-eggs/
16+
dist/
17+
downloads/
18+
eggs/
19+
.eggs/
20+
lib/
21+
lib64/
22+
parts/
23+
sdist/
24+
var/
25+
wheels/
26+
share/python-wheels/
27+
*.egg-info/
28+
.installed.cfg
29+
*.egg
30+
MANIFEST
31+
32+
# Environments
33+
.venv
34+
.env
35+
36+
# mypy
37+
.mypy_cache/
38+
.dmypy.json
39+
dmypy.json

0 commit comments

Comments
 (0)