Skip to content

Commit a6d2403

Browse files
committed
WS1
.github/workflows/ci.yml: .gitignore: codetracer-python-recorder/LICENSE: codetracer-python-recorder/README.md: codetracer-python-recorder/pyproject.toml: design-docs/codetracer-python-recorder-pypi-release-checklist.md: design-docs/codetracer-python-recorder-pypi-release-implementation-plan.status.md: scripts/check_recorder_version.py: Signed-off-by: Tzanko Matev <[email protected]>
1 parent 0cca060 commit a6d2403

File tree

8 files changed

+175
-2
lines changed

8 files changed

+175
-2
lines changed

.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

.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

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

codetracer-python-recorder/pyproject.toml

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,54 @@ name = "codetracer-python-recorder"
33
version = "0.1.0"
44
description = "Low-level Rust-backed Python module for CodeTracer recording (PyO3)"
55
authors = [{name = "Metacraft Labs Ltd"}]
6-
license = {text = "MIT"}
7-
requires-python = ">=3.8"
6+
license = {file = "LICENSE"}
7+
readme = "README.md"
8+
requires-python = ">=3.12,<3.14"
89
classifiers = [
10+
"Development Status :: 4 - Beta",
11+
"Intended Audience :: Developers",
912
"License :: OSI Approved :: MIT License",
1013
"Programming Language :: Python :: 3",
1114
"Programming Language :: Python :: 3 :: Only",
15+
"Programming Language :: Python :: Implementation :: CPython",
16+
"Programming Language :: Python :: 3.12",
17+
"Programming Language :: Python :: 3.13",
1218
"Programming Language :: Rust",
19+
"Operating System :: Microsoft :: Windows",
20+
"Operating System :: MacOS",
21+
"Operating System :: POSIX :: Linux",
22+
"Topic :: Software Development :: Debuggers",
1323
]
1424

1525
[project.scripts]
1626
codetracer-python-recorder = "codetracer_python_recorder.cli:main"
1727

28+
[project.urls]
29+
Homepage = "https://github.com/metacraft-labs/codetracer-python-recorder/tree/main/codetracer-python-recorder"
30+
Repository = "https://github.com/metacraft-labs/codetracer-python-recorder"
31+
Issues = "https://github.com/metacraft-labs/codetracer-python-recorder/issues"
32+
Changelog = "https://github.com/metacraft-labs/codetracer-python-recorder/releases"
33+
1834
[tool.maturin]
1935
# Build the PyO3 extension module
2036
bindings = "pyo3"
2137
# Use the library name as the Python import name: codetracer_python_recorder
2238

39+
[tool.maturin.sdist]
40+
include = [
41+
"Cargo.lock",
42+
"Cargo.toml",
43+
"LICENSE",
44+
"README.md",
45+
"pyproject.toml",
46+
"src/**",
47+
"codetracer_python_recorder/**",
48+
]
49+
exclude = [
50+
"target/**",
51+
"codetracer_python_recorder/*.so",
52+
]
53+
2354
[build-system]
2455
requires = ["maturin>=1.5,<2"]
2556
build-backend = "maturin"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# `codetracer-python-recorder` PyPI Release Checklist
2+
3+
1. **Plan the release**
4+
- Confirm target version and ensure the changelog/release notes cover all user-visible changes.
5+
- Review open issues for blockers and verify CI is green on `main`.
6+
2. **Update metadata**
7+
- Bump the version in both `codetracer-python-recorder/pyproject.toml` and `codetracer-python-recorder/Cargo.toml`.
8+
- Run `python scripts/check_recorder_version.py` to confirm parity.
9+
- Regenerate or update documentation if required (`README.md`, API docs).
10+
3. **Validate locally**
11+
- Execute `just venv 3.12 dev` (or preferred interpreter) and run `just test`.
12+
- Build wheels and sdist (`just build` or `maturin build --release --sdist`) and perform a smoke install in a clean virtualenv (`python -m pip install dist/*.whl` and run `python -m codetracer_python_recorder --help`).
13+
4. **Prepare the release tag**
14+
- Commit changes following Conventional Commits.
15+
- Tag the release with `git tag -a recorder-vX.Y.Z -m "codetracer-python-recorder vX.Y.Z"` and push (`git push origin recorder-vX.Y.Z`).
16+
5. **Trigger CI publishing**
17+
- Monitor the `recorder-release` workflow.
18+
- Verify that TestPyPI publishing succeeds and smoke tests pass on all platforms.
19+
6. **Promote to PyPI**
20+
- Approve the protected “Promote to PyPI” environment to publish the previously built artefacts.
21+
- Confirm the workflow completes without errors.
22+
7. **Post-release tasks**
23+
- Validate installation directly from PyPI on Linux, macOS, and Windows for Python 3.12 and 3.13.
24+
- Publish release notes (GitHub Release) and notify stakeholders.
25+
- Create follow-up issues for any tasks deferred from the release.
26+
27+
Refer to the Python Packaging User Guide packaging flow (<https://packaging.python.org/en/latest/flow/>)
28+
and the maturin distribution guide (<https://www.maturin.rs/distribution.html>) for further detail on
29+
packaging expectations.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# `codetracer-python-recorder` PyPI Release – Status
2+
3+
## Workstream 1 – Package metadata & repository hygiene
4+
- ✅ Tightened `pyproject.toml` metadata (Python 3.12–3.13 targets, classifiers, README long description, license file).
5+
- ✅ Added maturin sdist include/exclude rules and a dedicated LICENSE copy for the crate.
6+
- ✅ Introduced `scripts/check_recorder_version.py` and wired it into CI to enforce version parity.
7+
- ✅ Documented supported environments in `codetracer-python-recorder/README.md` and added a release checklist under `design-docs/`.
8+
9+
## Next Tasks
10+
- Begin Workstream 2: enhance build/test automation (extend Just recipes, add smoke install target, ensure integration coverage).
11+
- Draft changes to the release workflow (`recorder-release.yml`) once Workstream 2 groundwork is ready.

scripts/check_recorder_version.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env python3
2+
"""Verify codetracer recorder version parity across Python and Rust manifests."""
3+
4+
from __future__ import annotations
5+
6+
import sys
7+
from pathlib import Path
8+
9+
try: # Python 3.11+
10+
import tomllib # type: ignore[attr-defined]
11+
except ModuleNotFoundError: # pragma: no cover - safety net for older interpreters
12+
tomllib = None # type: ignore[assignment]
13+
14+
REPO_ROOT = Path(__file__).resolve().parents[1]
15+
PYPROJECT = REPO_ROOT / "codetracer-python-recorder" / "pyproject.toml"
16+
CARGO = REPO_ROOT / "codetracer-python-recorder" / "Cargo.toml"
17+
18+
19+
def _read_version(path: Path, section: str) -> str:
20+
text = path.read_text(encoding="utf-8")
21+
if tomllib is not None:
22+
data = tomllib.loads(text)
23+
section_data = data.get(section)
24+
if not isinstance(section_data, dict):
25+
raise KeyError(f"Missing section [{section}] in {path}")
26+
version = section_data.get("version")
27+
if not isinstance(version, str):
28+
raise KeyError(f"Missing 'version' in [{section}] of {path}")
29+
return version
30+
31+
# Minimal parser fallback for environments without tomllib/tomli.
32+
target_header = f"[{section}]"
33+
in_section = False
34+
for raw_line in text.splitlines():
35+
line = raw_line.strip()
36+
if not line or line.startswith("#"):
37+
continue
38+
if line.startswith("[") and line.endswith("]"):
39+
in_section = line == target_header
40+
continue
41+
if in_section and line.startswith("version"):
42+
_, _, value = line.partition("=")
43+
version = value.strip().strip('"')
44+
if version:
45+
return version
46+
raise KeyError(f"Could not locate version in [{section}] of {path}")
47+
48+
49+
def main() -> int:
50+
python_version = _read_version(PYPROJECT, "project")
51+
rust_version = _read_version(CARGO, "package")
52+
if python_version != rust_version:
53+
sys.stderr.write(
54+
"Version mismatch detected:\n"
55+
f" pyproject.toml -> {python_version}\n"
56+
f" Cargo.toml -> {rust_version}\n"
57+
)
58+
return 1
59+
return 0
60+
61+
62+
if __name__ == "__main__":
63+
raise SystemExit(main())

0 commit comments

Comments
 (0)