Skip to content
This repository was archived by the owner on Jan 1, 2026. It is now read-only.

Commit e2cdcde

Browse files
committed
feat: add Python 3.13 support and modernize CI infrastructure
- Add Python 3.13 to the test matrix - Remove EOL platforms: - macOS 11 and 12 (replaced with macOS 13, 14, 15) - manylinux2014 (replaced with manylinux_2_28 only) - Upgrade GitHub Actions dependencies: - actions/cache v3 → v4 - actions/checkout v3 → v4 - actions/setup-python v3 → v4 - docker/setup-qemu-action → v3 - Add ARM64 (aarch64) architecture support via QEMU emulation - Refactor CI workflow to use simplified matrix configuration - Update dependencies to support Python 3.13 (cffi, etc.) - Add libffi-devel installation for manylinux_2_28 + Python 3.13 This modernizes the build infrastructure to support current Python versions and platforms while removing support for end-of-life environments.
1 parent ff20521 commit e2cdcde

6 files changed

Lines changed: 242 additions & 195 deletions

File tree

.github/actions/setup-mingw/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ inputs:
77
runs:
88
using: "composite"
99
steps:
10-
- uses: actions/cache@v3
10+
- uses: actions/cache@v4
1111
id: cache-mingw
1212
with:
1313
path: mingw

.github/actions/setup-poetry/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ runs:
2424
- run: echo "v=$(poetry --version | cut -d' ' -f3 | cut -d')' -f1)" >> "$GITHUB_OUTPUT"
2525
shell: bash
2626
id: poetry-version
27-
- uses: actions/cache@v3
27+
- uses: actions/cache@v4
2828
id: cache-poetry
2929
with:
3030
path: .venv

.github/workflows/main.yml

Lines changed: 113 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,180 +3,170 @@ name: Build, test, release
33
on:
44
push:
55
branches:
6-
- '*'
6+
- "*"
77
tags:
8-
- '[0-9]+.[0-9]+.[0-9]+'
9-
- '[0-9]+.[0-9]+.[0-9]+.dev[0-9]+'
10-
11-
env:
12-
PY_VERSIONS_STR: >-
13-
["3.8", "3.9", "3.10", "3.11", "3.12"]
14-
VERSIONS_LINUX_STR: >-
15-
["manylinux2014", "manylinux_2_28"]
16-
VERSIONS_MACOS_STR: >-
17-
["macos-11", "macos-12"]
18-
VERSIONS_WINDOWS_STR: >-
19-
["windows-2022"]
20-
8+
- "[0-9]+.[0-9]+.[0-9]+"
9+
- "[0-9]+.[0-9]+.[0-9]+.dev[0-9]+"
2110

2211
jobs:
23-
pass-env:
24-
runs-on: ubuntu-latest
25-
outputs:
26-
py-versions-str: ${{ steps.set-env.outputs.py_versions_str }}
27-
versions-linux-str: ${{ steps.set-env.outputs.versions_linux_str }}
28-
versions-macos-str: ${{ steps.set-env.outputs.versions_macos_str }}
29-
versions-windows-str: ${{ steps.set-env.outputs.versions_windows_str }}
30-
is-from-tag-str: ${{ steps.set-env.outputs.is_from_tag_str }}
31-
is-for-release-str: ${{ steps.set-env.outputs.is_for_release_str }}
32-
steps:
33-
- id: set-env
34-
run: |
35-
echo "py_versions_str=${{ toJSON(env.PY_VERSIONS_STR) }}" >> "$GITHUB_OUTPUT"
36-
echo "versions_linux_str=${{ toJSON(env.VERSIONS_LINUX_STR) }}" >> "$GITHUB_OUTPUT"
37-
echo "versions_macos_str=${{ toJSON(env.VERSIONS_MACOS_STR) }}" >> "$GITHUB_OUTPUT"
38-
echo "versions_windows_str=${{ toJSON(env.VERSIONS_WINDOWS_STR) }}" >> "$GITHUB_OUTPUT"
39-
echo "is_from_tag_str=${{ toJSON(github.ref_type == 'tag') }}" >> "$GITHUB_OUTPUT"
40-
echo "is_for_release_str=${{ toJSON(!contains(github.ref_name, 'dev')) }}" >> "$GITHUB_OUTPUT"
41-
build-linux:
42-
needs: pass-env
43-
strategy:
44-
fail-fast: false
45-
matrix:
46-
image-name: ${{ fromJSON(needs.pass-env.outputs.versions-linux-str) }}
47-
image-arch:
48-
- x86_64
49-
py-version: ${{ fromJSON(needs.pass-env.outputs.py-versions-str) }}
50-
runs-on: ubuntu-latest
51-
container:
52-
image: quay.io/pypa/${{ matrix.image-name }}_${{ matrix.image-arch }}
53-
steps:
54-
- uses: actions/checkout@v3
55-
with:
56-
submodules: true
57-
- uses: ./.github/actions/setup-poetry
58-
with:
59-
key-base: ${{ matrix.image-name }}_${{ matrix.image-arch }}-py${{ matrix.py-version }}
60-
use-pipx: true
61-
use-specific-python-version: true
62-
specific-python-version: ${{ matrix.py-version }}
63-
- run: make test
64-
- uses: ./.github/actions/upload-artifacts
65-
with:
66-
make-binary: true
67-
repair-manylinux: true
68-
manylinux-target: ${{ matrix.image-name}}_${{ matrix.image-arch }}
69-
if: ${{ fromJSON(needs.pass-env.outputs.is-from-tag-str) }}
70-
build-macos:
71-
needs: pass-env
72-
strategy:
73-
fail-fast: false
74-
matrix:
75-
arch: ${{ fromJSON(needs.pass-env.outputs.versions-macos-str) }}
76-
py-version: ${{ fromJSON(needs.pass-env.outputs.py-versions-str) }}
77-
runs-on: ${{ matrix.arch }}
78-
steps:
79-
- uses: actions/checkout@v3
80-
with:
81-
submodules: true
82-
- uses: actions/setup-python@v3
83-
with:
84-
python-version: ${{ matrix.py-version }}
85-
- uses: ./.github/actions/setup-poetry
86-
with:
87-
key-base: ${{ matrix.arch }}-py${{ matrix.py-version }}
88-
use-pipx: false
89-
use-specific-python-version: false
90-
- run: make test
91-
- uses: ./.github/actions/upload-artifacts
92-
with:
93-
make-binary: true
94-
if: ${{ fromJSON(needs.pass-env.outputs.is-from-tag-str) }}
95-
build-windows:
96-
needs: pass-env
12+
build:
9713
strategy:
9814
fail-fast: false
9915
matrix:
100-
arch: ${{ fromJSON(needs.pass-env.outputs.versions-windows-str) }}
101-
py-version: ${{ fromJSON(needs.pass-env.outputs.py-versions-str) }}
102-
runs-on: ${{ matrix.arch }}
16+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
17+
os: [ubuntu-latest, macos-13, macos-14, macos-15, windows-2022]
18+
manylinux: [null, "manylinux_2_28_x86_64", "manylinux_2_28_aarch64"]
19+
exclude:
20+
# Exclude manylinux for non-Linux platforms
21+
- os: macos-13
22+
manylinux: "manylinux_2_28_x86_64"
23+
- os: macos-13
24+
manylinux: "manylinux_2_28_aarch64"
25+
- os: macos-14
26+
manylinux: "manylinux_2_28_x86_64"
27+
- os: macos-14
28+
manylinux: "manylinux_2_28_aarch64"
29+
- os: macos-15
30+
manylinux: "manylinux_2_28_x86_64"
31+
- os: macos-15
32+
manylinux: "manylinux_2_28_aarch64"
33+
- os: windows-2022
34+
manylinux: "manylinux_2_28_x86_64"
35+
- os: windows-2022
36+
manylinux: "manylinux_2_28_aarch64"
37+
# Exclude null manylinux for Linux
38+
- os: ubuntu-latest
39+
manylinux: null
40+
41+
runs-on: ${{ matrix.os }}
42+
container: ${{ matrix.manylinux != 'manylinux_2_28_aarch64' && matrix.manylinux && format('quay.io/pypa/{0}', matrix.manylinux) || null }}
43+
10344
steps:
104-
- uses: actions/checkout@v3
45+
# Set up QEMU for aarch64 emulation
46+
- name: Set up QEMU
47+
uses: docker/setup-qemu-action@v3
48+
if: matrix.manylinux == 'manylinux_2_28_aarch64'
49+
50+
- uses: actions/checkout@v4
10551
with:
10652
submodules: true
53+
54+
# Install libffi-devel for manylinux_2_28 and Python 3.13
55+
- name: Install system dependencies
56+
if: matrix.manylinux == 'manylinux_2_28_x86_64' && matrix.python-version == '3.13'
57+
run: |
58+
yum install -y libffi-devel
59+
shell: bash
60+
61+
# Windows specific setup
10762
- uses: ./.github/actions/setup-mingw
63+
if: runner.os == 'Windows'
10864
with:
109-
key-base: ${{ matrix.arch }}-py${{ matrix.py-version }}
110-
- uses: actions/setup-python@v3
65+
key-base: ${{ matrix.os }}-py${{ matrix.python-version }}
66+
67+
# Setup Python (not for Linux containers)
68+
- uses: actions/setup-python@v4
69+
if: runner.os != 'Linux' || !matrix.manylinux
11170
with:
112-
python-version: ${{ matrix.py-version }}
71+
python-version: ${{ matrix.python-version }}
72+
11373
- uses: ./.github/actions/setup-poetry
74+
if: matrix.manylinux != 'manylinux_2_28_aarch64'
11475
with:
115-
key-base: ${{ matrix.arch }}-py${{ matrix.py-version }}
116-
use-pipx: false
117-
use-specific-python-version: false
76+
key-base: ${{ matrix.os }}-${{ matrix.manylinux || 'native' }}-py${{ matrix.python-version }}
77+
use-pipx: ${{ matrix.manylinux && 'true' || 'false' }}
78+
use-specific-python-version: ${{ matrix.manylinux && 'true' || 'false' }}
79+
specific-python-version: ${{ matrix.python-version }}
80+
81+
# Run tests for aarch64 in Docker
82+
- name: Run tests in aarch64 container
83+
if: matrix.manylinux == 'manylinux_2_28_aarch64'
84+
run: |
85+
docker run --rm -v ${{ github.workspace }}:/work -w /work \
86+
--platform linux/arm64 \
87+
quay.io/pypa/manylinux_2_28_aarch64 \
88+
bash -c "
89+
# Install Python if needed
90+
if ! command -v python${{ matrix.python-version }} &> /dev/null; then
91+
PYTHON_VERSION=\"${{ matrix.python-version }}\"
92+
yum install -y python\${PYTHON_VERSION//./-} python\${PYTHON_VERSION//./-}-devel
93+
fi
94+
95+
# Install pipx and poetry
96+
python${{ matrix.python-version }} -m pip install pipx
97+
python${{ matrix.python-version }} -m pipx install poetry
98+
export PATH=\"\$HOME/.local/bin:\$PATH\"
99+
100+
# Configure poetry
101+
poetry config --local virtualenvs.in-project true
102+
poetry env use python${{ matrix.python-version }}
103+
poetry install
104+
105+
# Run tests
106+
make test
107+
"
108+
109+
# Run tests
118110
- run: make test
111+
if: matrix.manylinux != 'manylinux_2_28_aarch64'
112+
113+
# Upload artifacts for tagged builds
119114
- uses: ./.github/actions/upload-artifacts
120115
with:
121116
make-binary: true
122-
if: ${{ fromJSON(needs.pass-env.outputs.is-from-tag-str) }}
117+
repair-manylinux: ${{ matrix.manylinux && 'true' || 'false' }}
118+
manylinux-target: ${{ matrix.manylinux }}
119+
if: github.ref_type == 'tag'
120+
123121
package-source:
124-
needs:
125-
- pass-env
126-
- build-linux
127-
- build-macos
128-
- build-windows
122+
needs: build
129123
runs-on: ubuntu-latest
130-
if: ${{ fromJSON(needs.pass-env.outputs.is-from-tag-str) }}
124+
if: github.ref_type == 'tag'
131125
steps:
132-
- uses: actions/checkout@v3
126+
- uses: actions/checkout@v4
133127
with:
134128
submodules: true
135-
- uses: actions/setup-python@v3
129+
- uses: actions/setup-python@v4
136130
with:
137-
python-version: ${{ fromJSON(needs.pass-env.outputs.py-versions-str)[0] }}
131+
python-version: "3.8"
138132
- uses: ./.github/actions/setup-poetry
139133
with:
140-
key-base: source_linux-py${{ fromJSON(needs.pass-env.outputs.py-versions-str)[0] }}
134+
key-base: source_linux-py3.8
141135
use-pipx: false
142136
use-specific-python-version: false
143137
- uses: ./.github/actions/upload-artifacts
144138
with:
145139
make-binary: false
140+
146141
upload-pypi:
147-
needs:
148-
- pass-env
149-
- build-linux
150-
- build-macos
151-
- build-windows
152-
- package-source
142+
needs: [build, package-source]
153143
runs-on: ubuntu-latest
154-
if: ${{ fromJSON(needs.pass-env.outputs.is-from-tag-str) }}
144+
if: github.ref_type == 'tag'
155145
steps:
156-
- uses: actions/checkout@v3
146+
- uses: actions/checkout@v4
157147
with:
158148
submodules: true
159-
- uses: actions/setup-python@v3
149+
- uses: actions/setup-python@v4
160150
with:
161-
python-version: ${{ fromJSON(needs.pass-env.outputs.py-versions-str)[0] }}
162-
- uses: actions/download-artifact@v2
151+
python-version: "3.8"
152+
- uses: actions/download-artifact@v3
163153
with:
164154
path: dist
165155
- uses: ./.github/actions/setup-poetry
166156
with:
167-
key-base: source_linux-py${{ fromJSON(needs.pass-env.outputs.py-versions-str)[0] }}
157+
key-base: source_linux-py3.8
168158
use-pipx: false
169159
use-specific-python-version: false
170160
- uses: pypa/gh-action-pypi-publish@release/v1
171161
with:
172162
user: __token__
173163
password: ${{ secrets.PYPI_API_TOKEN }}
174164
packages_dir: dist/artifact/
175-
if: ${{ fromJSON(needs.pass-env.outputs.is-for-release-str) }}
165+
if: ${{ !contains(github.ref_name, 'dev') }}
176166
- uses: pypa/gh-action-pypi-publish@release/v1
177167
with:
178168
user: __token__
179169
password: ${{ secrets.TESTPYPI_API_TOKEN }}
180170
packages_dir: dist/artifact/
181171
repository_url: https://test.pypi.org/legacy/
182-
if: ${{ !fromJSON(needs.pass-env.outputs.is-for-release-str) }}
172+
if: ${{ contains(github.ref_name, 'dev') }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ dist
44
quickjs.egg-info
55
*.so
66
*.pyd
7+
/venv

0 commit comments

Comments
 (0)