Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/ISSUE_TEMPLATE/recorder-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Recorder Release Tracker
description: Plan, execute, and verify a codetracer-python-recorder release
title: "Release: codetracer-python-recorder vX.Y.Z"
labels: ["release", "codetracer-python-recorder"]
body:
- type: markdown
attributes:
value: >
Use this issue to coordinate a release of `codetracer-python-recorder`.
Follow the release checklist in `design-docs/codetracer-python-recorder-pypi-release-checklist.md`
and record progress below.
- type: input
id: version
attributes:
label: Target version
description: The version you plan to publish (e.g., 0.2.0)
placeholder: 0.2.0
validations:
required: true
- type: textarea
id: planning
attributes:
label: Pre-release planning notes
description: Capture any blockers, feature highlights, or coordination tasks.
placeholder: >
- Pending PRs
- Docs to update
- Coordination with downstream teams
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: >
Tick each item as you complete the steps in the release checklist.
Reference links or PRs next to each item where useful.
options:
- label: Changelog updated and version bumped (pyproject.toml / Cargo.toml)
- label: Local validation complete (`just test`, `just smoke-wheel`)
- label: Annotated tag pushed (`recorder-vX.Y.Z`)
- label: TestPyPI workflow run passed and smoke install verified
- label: PyPI promotion approved and workflow completed
- label: Post-release validation on Linux, macOS, Windows (3.12 / 3.13)
- label: Release notes published and stakeholders notified
- type: textarea
id: retrospective
attributes:
label: Post-release notes
description: >
Document any follow-up work, incidents, or improvements spotted during the release.
placeholder: >
- Follow-up issue: ...
- Automation improvement: ...
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
- name: Prepare dev environment
run: nix develop --command bash -lc 'just venv ${{matrix.python-version}} dev'

- name: Verify recorder version metadata
run: nix develop --command bash -lc 'python3 scripts/check_recorder_version.py'

- name: Rust tests
run: nix develop --command bash -lc 'just cargo-test'

Expand Down
222 changes: 222 additions & 0 deletions .github/workflows/recorder-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
name: Recorder Release

on:
push:
tags:
- recorder-v*
workflow_dispatch:

permissions:
contents: read
id-token: write

concurrency:
group: recorder-release-${{ github.ref }}
cancel-in-progress: false

env:
CRATE_DIR: codetracer-python-recorder

jobs:
verify:
name: Verify Tests (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-25.05
extra_nix_config: |
experimental-features = nix-command flakes
- name: Prepare dev environment (Python 3.13)
run: nix develop --command bash -lc 'just venv 3.13 dev'
- name: Run test suite
run: nix develop --command bash -lc 'just test'
- name: Check recorder version parity
run: nix develop --command bash -lc 'python3 scripts/check_recorder_version.py'

build:
name: Build Artefacts (${{ matrix.name }})
needs: verify
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: linux-x86_64
os: ubuntu-latest
build-sdist: true
publish-args: --release --sdist --interpreter python3.12 python3.13
manylinux: 2014
- name: linux-aarch64
os: ubuntu-latest
build-sdist: false
publish-args: --release --interpreter python3.12 python3.13 --target aarch64-unknown-linux-gnu
manylinux: 2014
- name: macos-universal2
os: macos-13
build-sdist: false
publish-args: --release --universal2
- name: windows-amd64
os: windows-latest
build-sdist: false
publish-args: --release
steps:
- uses: actions/checkout@v4
- name: Check recorder version parity
shell: bash
run: |
PYTHON=$(command -v python3 || command -v python)
"$PYTHON" scripts/check_recorder_version.py
- name: Extract package version
id: version
shell: bash
run: |
PYTHON=$(command -v python3 || command -v python)
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'])")
echo "package_version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Assert tag matches version
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG="${GITHUB_REF##*/}"
EXPECTED="recorder-v${{ steps.version.outputs.package_version }}"
if [ "$TAG" != "$EXPECTED" ]; then
echo "::error::Tag '$TAG' does not match package version '$EXPECTED'"
exit 1
fi

- name: Build artefacts (Linux targets)
if: startsWith(matrix.name, 'linux-')
uses: messense/maturin-action@v1
with:
command: build
args: ${{ matrix.publish-args }}
manylinux: ${{ matrix.manylinux }}

- name: Install Python 3.12 (macOS)
if: startsWith(matrix.name, 'macos')
id: mac_py312
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Python 3.13 (macOS)
if: startsWith(matrix.name, 'macos')
id: mac_py313
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install Python 3.12 (Windows)
if: matrix.name == 'windows-amd64'
id: win_py312
uses: actions/setup-python@v5
with:
python-version: '3.12'
architecture: 'x64'

- name: Install Python 3.13 (Windows)
if: matrix.name == 'windows-amd64'
id: win_py313
uses: actions/setup-python@v5
with:
python-version: '3.13'
architecture: 'x64'

- name: Install maturin (macOS)
if: startsWith(matrix.name, 'macos')
run: python3 -m pip install --upgrade pip maturin>=1.5,<2

- name: Install maturin (Windows)
if: matrix.name == 'windows-amd64'
run: python -m pip install --upgrade pip maturin>=1.5,<2

- name: Build artefacts (macOS universal2)
if: startsWith(matrix.name, 'macos')
env:
PYTHON312: ${{ steps.mac_py312.outputs.python-path }}
PYTHON313: ${{ steps.mac_py313.outputs.python-path }}
working-directory: ${{ env.CRATE_DIR }}
run: maturin build ${{ matrix.publish-args }} --interpreter "$PYTHON312" "$PYTHON313"

- name: Build cp312 wheel (Windows)
if: matrix.name == 'windows-amd64'
env:
PYTHON: ${{ steps.win_py312.outputs.python-path }}
working-directory: ${{ env.CRATE_DIR }}
run: maturin build --release --interpreter "$env:PYTHON"

- name: Build cp313 wheel (Windows)
if: matrix.name == 'windows-amd64'
env:
PYTHON: ${{ steps.win_py313.outputs.python-path }}
working-directory: ${{ env.CRATE_DIR }}
run: maturin build --release --interpreter "$env:PYTHON"

- name: Upload artefacts
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.name }}
path: |
codetracer-python-recorder/target/wheels/*
if-no-files-found: error

publish-testpypi:
name: Publish to TestPyPI
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Download artefacts
uses: actions/download-artifact@v4
with:
pattern: dist-*
path: dist
merge-multiple: true
- name: Inspect artefacts
run: ls -R dist
- name: Install maturin
run: python3 -m pip install --upgrade pip maturin>=1.5,<2
- name: Python smoke install (Linux wheel)
run: |
python3 scripts/check_recorder_version.py
FILE=$(python3 scripts/select_recorder_artifact.py --wheel-dir dist --mode wheel --platform linux)
python3 -m venv .smoke
. .smoke/bin/activate
pip install --upgrade pip
pip install "$FILE"
python -m codetracer_python_recorder --help
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: dist

publish-pypi:
name: Publish to PyPI
needs: publish-testpypi
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
environment:
name: pypi-production
url: https://pypi.org/project/codetracer-python-recorder/
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Download artefacts
uses: actions/download-artifact@v4
with:
pattern: dist-*
path: dist
merge-multiple: true
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ build
.cargo/

**/*.egg-info/
codetracer-python-recorder/codetracer_python_recorder/*.so
21 changes: 18 additions & 3 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ coverage-python:

# Build the module in release mode
build:
just venv \
uv run --directory codetracer-python-recorder maturin build --release
just venv
uv run --directory codetracer-python-recorder maturin build --release --sdist

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

# Smoke the built Rust wheels across versions using uv
test-all:
Expand All @@ -82,3 +82,18 @@ test-all:
file="${file[0]}"; \
uv run -p "python3.$v" --with "${file}" --with pytest -- pytest -q; \
done

# Install a freshly built artifact and run a CLI smoke test
smoke-wheel artifact="wheel" interpreter=".venv/bin/python":
just build
VENV_DIR="$(mktemp -d)"; \
trap 'rm -rf "$VENV_DIR"' EXIT; \
"{{interpreter}}" -m venv "$VENV_DIR"; \
VENV_PY="$VENV_DIR/bin/python"; \
if [ ! -x "$VENV_PY" ]; then \
VENV_PY="$VENV_DIR/Scripts/python.exe"; \
fi; \
"$VENV_PY" -m pip install --upgrade pip; \
FILE="$("$VENV_PY" scripts/select_recorder_artifact.py --wheel-dir codetracer-python-recorder/target/wheels --mode "{{artifact}}")"; \
"$VENV_PY" -m pip install "$FILE"; \
"$VENV_PY" -m codetracer_python_recorder --help >/dev/null
19 changes: 19 additions & 0 deletions codetracer-python-recorder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

All notable changes to `codetracer-python-recorder` will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2025-10-13

### Added
- Initial public release of the Rust-backed recorder with PyO3 bindings.
- Python façade (`codetracer_python_recorder`) exposing `start`, `stop`, `trace`,
and CLI entry point (`python -m codetracer_python_recorder`).
- Support for generating `trace_metadata.json` and `trace_paths.json`
artefacts compatible with the Codetracer db-backend importer.
- Cross-platform packaging definition targeting CPython 3.12 and 3.13 on
Linux (manylinux2014 `x86_64`/`aarch64`), macOS universal2, and Windows `amd64`.

[0.1.0]: https://github.com/metacraft-labs/cpr-main/releases/tag/recorder-v0.1.0
21 changes: 21 additions & 0 deletions codetracer-python-recorder/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Metacraft Labs Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
14 changes: 14 additions & 0 deletions codetracer-python-recorder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ tracing inside Codetracer. The PyO3 extension exposes a small Python façade so
packaged environments (desktop bundles, `uv run`, virtualenvs) can start and stop
recording without shipping an additional interpreter.

## Installation

`codetracer-python-recorder` publishes binary wheels for CPython 3.12 and 3.13 on
Linux (manylinux2014 `x86_64`/`aarch64`), macOS 11+ universal2 (`arm64` + `x86_64`),
and Windows 10+ (`win_amd64`). Install the package into the interpreter you plan to
trace:

```bash
python -m pip install codetracer-python-recorder
```

Source distributions are available for audit and custom builds; maturin and a Rust
toolchain are required when building from source.

## Command-line entry point

The wheel installs a console script named `codetracer-python-recorder` and the
Expand Down
Loading
Loading