Skip to content

Commit ebab9de

Browse files
authored
Pypi integration (#50)
2 parents b7aaed1 + 0f7318c commit ebab9de

18 files changed

+866
-317
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Recorder Release Tracker
2+
description: Plan, execute, and verify a codetracer-python-recorder release
3+
title: "Release: codetracer-python-recorder vX.Y.Z"
4+
labels: ["release", "codetracer-python-recorder"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: >
9+
Use this issue to coordinate a release of `codetracer-python-recorder`.
10+
Follow the release checklist in `design-docs/codetracer-python-recorder-pypi-release-checklist.md`
11+
and record progress below.
12+
- type: input
13+
id: version
14+
attributes:
15+
label: Target version
16+
description: The version you plan to publish (e.g., 0.2.0)
17+
placeholder: 0.2.0
18+
validations:
19+
required: true
20+
- type: textarea
21+
id: planning
22+
attributes:
23+
label: Pre-release planning notes
24+
description: Capture any blockers, feature highlights, or coordination tasks.
25+
placeholder: >
26+
- Pending PRs
27+
- Docs to update
28+
- Coordination with downstream teams
29+
- type: checkboxes
30+
id: checklist
31+
attributes:
32+
label: Checklist
33+
description: >
34+
Tick each item as you complete the steps in the release checklist.
35+
Reference links or PRs next to each item where useful.
36+
options:
37+
- label: Changelog updated and version bumped (pyproject.toml / Cargo.toml)
38+
- label: Local validation complete (`just test`, `just smoke-wheel`)
39+
- label: Annotated tag pushed (`recorder-vX.Y.Z`)
40+
- label: TestPyPI workflow run passed and smoke install verified
41+
- label: PyPI promotion approved and workflow completed
42+
- label: Post-release validation on Linux, macOS, Windows (3.12 / 3.13)
43+
- label: Release notes published and stakeholders notified
44+
- type: textarea
45+
id: retrospective
46+
attributes:
47+
label: Post-release notes
48+
description: >
49+
Document any follow-up work, incidents, or improvements spotted during the release.
50+
placeholder: >
51+
- Follow-up issue: ...
52+
- Automation improvement: ...

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ jobs:
2525
- name: Prepare dev environment
2626
run: nix develop --command bash -lc 'just venv ${{matrix.python-version}} dev'
2727

28+
- name: Verify recorder version metadata
29+
run: nix develop --command bash -lc 'python3 scripts/check_recorder_version.py'
30+
2831
- name: Rust tests
2932
run: nix develop --command bash -lc 'just cargo-test'
3033

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
name: Recorder Release
2+
3+
on:
4+
push:
5+
tags:
6+
- recorder-v*
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
id-token: write
12+
13+
concurrency:
14+
group: recorder-release-${{ github.ref }}
15+
cancel-in-progress: false
16+
17+
env:
18+
CRATE_DIR: codetracer-python-recorder
19+
20+
jobs:
21+
verify:
22+
name: Verify Tests (Linux)
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
- uses: cachix/install-nix-action@v27
27+
with:
28+
nix_path: nixpkgs=channel:nixos-25.05
29+
extra_nix_config: |
30+
experimental-features = nix-command flakes
31+
- name: Prepare dev environment (Python 3.13)
32+
run: nix develop --command bash -lc 'just venv 3.13 dev'
33+
- name: Run test suite
34+
run: nix develop --command bash -lc 'just test'
35+
- name: Check recorder version parity
36+
run: nix develop --command bash -lc 'python3 scripts/check_recorder_version.py'
37+
38+
build:
39+
name: Build Artefacts (${{ matrix.name }})
40+
needs: verify
41+
runs-on: ${{ matrix.os }}
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
include:
46+
- name: linux-x86_64
47+
os: ubuntu-latest
48+
build-sdist: true
49+
publish-args: --release --sdist --interpreter python3.12 python3.13
50+
manylinux: 2014
51+
- name: linux-aarch64
52+
os: ubuntu-latest
53+
build-sdist: false
54+
publish-args: --release --interpreter python3.12 python3.13 --target aarch64-unknown-linux-gnu
55+
manylinux: 2014
56+
- name: macos-universal2
57+
os: macos-13
58+
build-sdist: false
59+
publish-args: --release --universal2
60+
- name: windows-amd64
61+
os: windows-latest
62+
build-sdist: false
63+
publish-args: --release
64+
steps:
65+
- uses: actions/checkout@v4
66+
- name: Check recorder version parity
67+
shell: bash
68+
run: |
69+
PYTHON=$(command -v python3 || command -v python)
70+
"$PYTHON" scripts/check_recorder_version.py
71+
- name: Extract package version
72+
id: version
73+
shell: bash
74+
run: |
75+
PYTHON=$(command -v python3 || command -v python)
76+
VERSION=$("$PYTHON" -c "import importlib, pathlib; tomllib = importlib.import_module('tomllib'); data = tomllib.loads(pathlib.Path('codetracer-python-recorder/pyproject.toml').read_text()); print(data['project']['version'])")
77+
echo "package_version=${VERSION}" >> "$GITHUB_OUTPUT"
78+
- name: Assert tag matches version
79+
if: startsWith(github.ref, 'refs/tags/')
80+
run: |
81+
TAG="${GITHUB_REF##*/}"
82+
EXPECTED="recorder-v${{ steps.version.outputs.package_version }}"
83+
if [ "$TAG" != "$EXPECTED" ]; then
84+
echo "::error::Tag '$TAG' does not match package version '$EXPECTED'"
85+
exit 1
86+
fi
87+
88+
- name: Build artefacts (Linux targets)
89+
if: startsWith(matrix.name, 'linux-')
90+
uses: messense/maturin-action@v1
91+
with:
92+
command: build
93+
args: ${{ matrix.publish-args }}
94+
manylinux: ${{ matrix.manylinux }}
95+
96+
- name: Install Python 3.12 (macOS)
97+
if: startsWith(matrix.name, 'macos')
98+
id: mac_py312
99+
uses: actions/setup-python@v5
100+
with:
101+
python-version: '3.12'
102+
103+
- name: Install Python 3.13 (macOS)
104+
if: startsWith(matrix.name, 'macos')
105+
id: mac_py313
106+
uses: actions/setup-python@v5
107+
with:
108+
python-version: '3.13'
109+
110+
- name: Install Python 3.12 (Windows)
111+
if: matrix.name == 'windows-amd64'
112+
id: win_py312
113+
uses: actions/setup-python@v5
114+
with:
115+
python-version: '3.12'
116+
architecture: 'x64'
117+
118+
- name: Install Python 3.13 (Windows)
119+
if: matrix.name == 'windows-amd64'
120+
id: win_py313
121+
uses: actions/setup-python@v5
122+
with:
123+
python-version: '3.13'
124+
architecture: 'x64'
125+
126+
- name: Install maturin (macOS)
127+
if: startsWith(matrix.name, 'macos')
128+
run: python3 -m pip install --upgrade pip maturin>=1.5,<2
129+
130+
- name: Install maturin (Windows)
131+
if: matrix.name == 'windows-amd64'
132+
run: python -m pip install --upgrade pip maturin>=1.5,<2
133+
134+
- name: Build artefacts (macOS universal2)
135+
if: startsWith(matrix.name, 'macos')
136+
env:
137+
PYTHON312: ${{ steps.mac_py312.outputs.python-path }}
138+
PYTHON313: ${{ steps.mac_py313.outputs.python-path }}
139+
working-directory: ${{ env.CRATE_DIR }}
140+
run: maturin build ${{ matrix.publish-args }} --interpreter "$PYTHON312" "$PYTHON313"
141+
142+
- name: Build cp312 wheel (Windows)
143+
if: matrix.name == 'windows-amd64'
144+
env:
145+
PYTHON: ${{ steps.win_py312.outputs.python-path }}
146+
working-directory: ${{ env.CRATE_DIR }}
147+
run: maturin build --release --interpreter "$env:PYTHON"
148+
149+
- name: Build cp313 wheel (Windows)
150+
if: matrix.name == 'windows-amd64'
151+
env:
152+
PYTHON: ${{ steps.win_py313.outputs.python-path }}
153+
working-directory: ${{ env.CRATE_DIR }}
154+
run: maturin build --release --interpreter "$env:PYTHON"
155+
156+
- name: Upload artefacts
157+
uses: actions/upload-artifact@v4
158+
with:
159+
name: dist-${{ matrix.name }}
160+
path: |
161+
codetracer-python-recorder/target/wheels/*
162+
if-no-files-found: error
163+
164+
publish-testpypi:
165+
name: Publish to TestPyPI
166+
needs: build
167+
runs-on: ubuntu-latest
168+
environment:
169+
name: testpypi
170+
steps:
171+
- uses: actions/checkout@v4
172+
- uses: actions/setup-python@v5
173+
with:
174+
python-version: '3.12'
175+
- name: Download artefacts
176+
uses: actions/download-artifact@v4
177+
with:
178+
pattern: dist-*
179+
path: dist
180+
merge-multiple: true
181+
- name: Inspect artefacts
182+
run: ls -R dist
183+
- name: Install maturin
184+
run: python3 -m pip install --upgrade pip maturin>=1.5,<2
185+
- name: Python smoke install (Linux wheel)
186+
run: |
187+
python3 scripts/check_recorder_version.py
188+
FILE=$(python3 scripts/select_recorder_artifact.py --wheel-dir dist --mode wheel --platform linux)
189+
python3 -m venv .smoke
190+
. .smoke/bin/activate
191+
pip install --upgrade pip
192+
pip install "$FILE"
193+
python -m codetracer_python_recorder --help
194+
- name: Publish to TestPyPI
195+
uses: pypa/gh-action-pypi-publish@release/v1
196+
with:
197+
repository-url: https://test.pypi.org/legacy/
198+
packages-dir: dist
199+
200+
publish-pypi:
201+
name: Publish to PyPI
202+
needs: publish-testpypi
203+
if: startsWith(github.ref, 'refs/tags/')
204+
runs-on: ubuntu-latest
205+
environment:
206+
name: pypi-production
207+
url: https://pypi.org/project/codetracer-python-recorder/
208+
steps:
209+
- uses: actions/checkout@v4
210+
- uses: actions/setup-python@v5
211+
with:
212+
python-version: '3.12'
213+
- name: Download artefacts
214+
uses: actions/download-artifact@v4
215+
with:
216+
pattern: dist-*
217+
path: dist
218+
merge-multiple: true
219+
- name: Publish to PyPI
220+
uses: pypa/gh-action-pypi-publish@release/v1
221+
with:
222+
packages-dir: dist

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ build
99
.cargo/
1010

1111
**/*.egg-info/
12+
codetracer-python-recorder/codetracer_python_recorder/*.so

Justfile

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ coverage-python:
6767

6868
# Build the module in release mode
6969
build:
70-
just venv \
71-
uv run --directory codetracer-python-recorder maturin build --release
70+
just venv
71+
uv run --directory codetracer-python-recorder maturin build --release --sdist
7272

7373
# Build wheels for all target Python versions with maturin
7474
build-all:
7575
just venv
76-
uv run --directory codetracer-python-recorder maturin build --release --interpreter {{PY_VERSIONS}}
76+
uv run --directory codetracer-python-recorder maturin build --release --sdist --interpreter {{PY_VERSIONS}}
7777

7878
# Smoke the built Rust wheels across versions using uv
7979
test-all:
@@ -82,3 +82,18 @@ test-all:
8282
file="${file[0]}"; \
8383
uv run -p "python3.$v" --with "${file}" --with pytest -- pytest -q; \
8484
done
85+
86+
# Install a freshly built artifact and run a CLI smoke test
87+
smoke-wheel artifact="wheel" interpreter=".venv/bin/python":
88+
just build
89+
VENV_DIR="$(mktemp -d)"; \
90+
trap 'rm -rf "$VENV_DIR"' EXIT; \
91+
"{{interpreter}}" -m venv "$VENV_DIR"; \
92+
VENV_PY="$VENV_DIR/bin/python"; \
93+
if [ ! -x "$VENV_PY" ]; then \
94+
VENV_PY="$VENV_DIR/Scripts/python.exe"; \
95+
fi; \
96+
"$VENV_PY" -m pip install --upgrade pip; \
97+
FILE="$("$VENV_PY" scripts/select_recorder_artifact.py --wheel-dir codetracer-python-recorder/target/wheels --mode "{{artifact}}")"; \
98+
"$VENV_PY" -m pip install "$FILE"; \
99+
"$VENV_PY" -m codetracer_python_recorder --help >/dev/null
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
All notable changes to `codetracer-python-recorder` will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - 2025-10-13
9+
10+
### Added
11+
- Initial public release of the Rust-backed recorder with PyO3 bindings.
12+
- Python façade (`codetracer_python_recorder`) exposing `start`, `stop`, `trace`,
13+
and CLI entry point (`python -m codetracer_python_recorder`).
14+
- Support for generating `trace_metadata.json` and `trace_paths.json`
15+
artefacts compatible with the Codetracer db-backend importer.
16+
- Cross-platform packaging definition targeting CPython 3.12 and 3.13 on
17+
Linux (manylinux2014 `x86_64`/`aarch64`), macOS universal2, and Windows `amd64`.
18+
19+
[0.1.0]: https://github.com/metacraft-labs/cpr-main/releases/tag/recorder-v0.1.0

codetracer-python-recorder/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Metacraft Labs Ltd
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

codetracer-python-recorder/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ tracing inside Codetracer. The PyO3 extension exposes a small Python façade so
55
packaged environments (desktop bundles, `uv run`, virtualenvs) can start and stop
66
recording without shipping an additional interpreter.
77

8+
## Installation
9+
10+
`codetracer-python-recorder` publishes binary wheels for CPython 3.12 and 3.13 on
11+
Linux (manylinux2014 `x86_64`/`aarch64`), macOS 11+ universal2 (`arm64` + `x86_64`),
12+
and Windows 10+ (`win_amd64`). Install the package into the interpreter you plan to
13+
trace:
14+
15+
```bash
16+
python -m pip install codetracer-python-recorder
17+
```
18+
19+
Source distributions are available for audit and custom builds; maturin and a Rust
20+
toolchain are required when building from source.
21+
822
## Command-line entry point
923

1024
The wheel installs a console script named `codetracer-python-recorder` and the

0 commit comments

Comments
 (0)