toolframe-testkit 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/.github/workflows/ci.yml +1 -1
  2. toolframe_testkit-0.2.0/.github/workflows/quality.yml +63 -0
  3. toolframe_testkit-0.2.0/.pre-commit-config.yaml +29 -0
  4. toolframe_testkit-0.2.0/CONTRIBUTING.md +49 -0
  5. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/PKG-INFO +6 -4
  6. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/README.md +4 -2
  7. toolframe_testkit-0.2.0/cchk.toml +10 -0
  8. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/docs/development.md +18 -19
  9. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/docs/harness.md +2 -2
  10. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/docs/releasing.md +2 -2
  11. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/examples/installed_application.py +2 -2
  12. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/pyproject.toml +2 -2
  13. toolframe_testkit-0.2.0/scripts/check_branch_name.py +59 -0
  14. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/scripts/smoke_wheel.py +1 -1
  15. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/src/toolframe_testkit/__init__.py +1 -1
  16. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/pyproject.toml +1 -1
  17. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/src/fixture_records/definition.py +1 -1
  18. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/src/fixture_records/service.py +3 -3
  19. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/test_installed_core.py +1 -1
  20. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/uv.lock +2 -2
  21. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/.github/workflows/publish.yml +0 -0
  22. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/.gitignore +0 -0
  23. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/LICENSE +0 -0
  24. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/conftest.py +0 -0
  25. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/docs/contracts.md +0 -0
  26. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/examples/check_fixture.py +0 -0
  27. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/scripts/validate_release.py +0 -0
  28. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/src/toolframe_testkit/contracts.py +0 -0
  29. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/src/toolframe_testkit/harness.py +0 -0
  30. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/src/toolframe_testkit/py.typed +0 -0
  31. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/src/toolframe_testkit/pytest_plugin.py +0 -0
  32. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/LICENSE +0 -0
  33. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/src/fixture_records/__init__.py +0 -0
  34. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/src/fixture_records/docs/usage.md +0 -0
  35. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/assets/service-plugin/src/fixture_records/migrations/0001_init.sql +0 -0
  36. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/test_contracts.py +0 -0
  37. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/test_harness_http.py +0 -0
  38. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/test_harness_process.py +0 -0
  39. {toolframe_testkit-0.1.2 → toolframe_testkit-0.2.0}/tests/test_pytest_plugin.py +0 -0
@@ -2,7 +2,7 @@ name: Validate Python distribution
2
2
 
3
3
  on:
4
4
  push:
5
- branches: ['**']
5
+ branches: [main]
6
6
  pull_request:
7
7
  workflow_dispatch:
8
8
  workflow_call:
@@ -0,0 +1,63 @@
1
+ name: Code quality
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ types: [opened, synchronize, reopened, edited]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ branch-policy:
15
+ runs-on: ubuntu-24.04
16
+ timeout-minutes: 5
17
+ steps:
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ with:
20
+ persist-credentials: false
21
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
22
+ with:
23
+ python-version: '3.14.7'
24
+ - name: Check the actual source branch
25
+ env:
26
+ BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
27
+ run: python scripts/check_branch_name.py "$BRANCH_NAME"
28
+
29
+ code-quality:
30
+ runs-on: ubuntu-24.04
31
+ timeout-minutes: 10
32
+ steps:
33
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
34
+ with:
35
+ persist-credentials: false
36
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
37
+ with:
38
+ version: '0.12.8'
39
+ enable-cache: false
40
+ - name: Check Python lint and formatting
41
+ run: uvx prek==0.5.5 run ruff-check ruff-format --all-files --show-diff-on-failure
42
+
43
+ commit-policy:
44
+ if: github.event_name == 'pull_request'
45
+ runs-on: ubuntu-24.04
46
+ timeout-minutes: 10
47
+ permissions:
48
+ contents: read
49
+ pull-requests: read
50
+ steps:
51
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
+ with:
53
+ fetch-depth: 0
54
+ persist-credentials: false
55
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
56
+ with:
57
+ python-version: '3.14.7'
58
+ - uses: commit-check/commit-check-action@a61779784a953fd9047c001c102cfeac5cf26964 # commit-check 2.18.3
59
+ with:
60
+ message: true
61
+ branch: false
62
+ pr-title: true
63
+ pr-comments: false
@@ -0,0 +1,29 @@
1
+ default_install_hook_types: [pre-commit, commit-msg]
2
+ default_stages: [pre-commit]
3
+ default_language_version:
4
+ python: python3.11
5
+
6
+ repos:
7
+ - repo: local
8
+ hooks:
9
+ - id: check-branch-name
10
+ name: Check branch naming policy
11
+ entry: python scripts/check_branch_name.py
12
+ language: python
13
+ always_run: true
14
+ pass_filenames: false
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.17.0
17
+ hooks:
18
+ - id: ruff-check
19
+ types_or: [python, pyi]
20
+ files: '^(src|tests|scripts)/'
21
+ - id: ruff-format
22
+ types_or: [python, pyi]
23
+ args: [--check]
24
+ files: '^(src|tests|scripts)/'
25
+ - repo: https://github.com/commit-check/commit-check
26
+ rev: v2.18.3
27
+ hooks:
28
+ - id: check-message
29
+ stages: [commit-msg]
@@ -0,0 +1,49 @@
1
+ # Contributing
2
+
3
+ ## Commit hooks
4
+
5
+ Install [prek](https://prek.j178.dev/) and enable the repository's hooks:
6
+
7
+ ```sh
8
+ uv tool install prek==0.5.5
9
+ prek install --allow-missing-config
10
+ prek run --all-files
11
+ ```
12
+
13
+ The missing-config option allows older worktrees without this configuration to
14
+ keep working. Worktrees containing `.pre-commit-config.yaml` still run the checks.
15
+ The `pre-commit` hook checks the branch name, Python lint, and formatting. The
16
+ `commit-msg` hook checks Conventional Commits. Both Ruff hooks only check files;
17
+ they do not rewrite a commit's contents. Fix lint and formatting explicitly:
18
+
19
+ ```sh
20
+ uvx ruff==0.17.0 check --fix src tests scripts
21
+ uvx ruff==0.17.0 format src tests scripts
22
+ prek run --all-files
23
+ ```
24
+
25
+ The Ruff version and checked paths are pinned in
26
+ [the hook configuration](.pre-commit-config.yaml); the Python rules remain in
27
+ [pyproject.toml](pyproject.toml). CI uses these same hooks on all tracked files
28
+ within their configured paths. Existing package, integration, and release checks
29
+ run independently.
30
+
31
+ ## Branches and commits
32
+
33
+ [cchk.toml](cchk.toml) defines the allowed branch and commit types. Work branches
34
+ use `feat/`, `fix/`, `release/`, or `chore/`, followed by lowercase ASCII letters
35
+ and digits separated by single hyphens. Release versions may also contain dots,
36
+ as in `release/v1.2.0-rc.1`; every separator must have an alphanumeric character on
37
+ both sides. The default branch `main` is the standalone exception.
38
+
39
+ Commit types are independent of branch types: for example,
40
+ `docs: clarify setup` is valid on `chore/update-docs`. Commit-check uses Conventional
41
+ Commits with its default subject length of 5–80 characters. Pull requests check
42
+ their commits and title so the title can be used for a Conventional Commit when
43
+ squash merging.
44
+
45
+ Local hooks can be bypassed. CI reports `branch-policy`, `code-quality`, and
46
+ `commit-policy`; maintainers must configure required status checks separately to
47
+ make passing checks a merge requirement.
48
+
49
+ For package setup and broader verification, see [the development guide](docs/development.md).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: toolframe-testkit
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Public contract checks and installed-application tests for Toolframe developers
5
5
  Project-URL: Homepage, https://github.com/toolframe/toolframe-testkit
6
6
  Project-URL: Repository, https://github.com/toolframe/toolframe-testkit
@@ -15,7 +15,7 @@ Requires-Dist: jsonschema<5,>=4.23
15
15
  Requires-Dist: psutil<9,>=7
16
16
  Requires-Dist: pydantic<3,>=2.12.5
17
17
  Requires-Dist: tomlkit<1,>=0.13
18
- Requires-Dist: toolframe-sdk==0.3.0
18
+ Requires-Dist: toolframe-sdk==0.4.0
19
19
  Provides-Extra: pytest
20
20
  Requires-Dist: pytest<10,>=8; extra == 'pytest'
21
21
  Description-Content-Type: text/markdown
@@ -25,7 +25,7 @@ Description-Content-Type: text/markdown
25
25
  Toolframe testkit is a Python library for checking a plugin's public SDK contract
26
26
  and exercising an installed Toolframe Core application through its public CLI and
27
27
  HTTP APIs. It is a developer test dependency, not a Core runtime plugin. Version
28
- 0.1.2 supports Python 3.14 or newer and pins `toolframe-sdk==0.3.0`.
28
+ 0.2.0 supports Python 3.14 or newer and pins `toolframe-sdk==0.4.0`.
29
29
 
30
30
  The package is Apache-2.0 licensed. It does not install Core, choose a global
31
31
  application, or load a pytest plugin automatically.
@@ -35,7 +35,7 @@ application, or load a pytest plugin automatically.
35
35
  Install the checker and opt-in pytest integration from PyPI:
36
36
 
37
37
  ```sh
38
- python -m pip install 'toolframe-testkit[pytest]==0.1.2'
38
+ python -m pip install 'toolframe-testkit[pytest]==0.2.0'
39
39
  ```
40
40
 
41
41
  The SDK is installed as a dependency. See
@@ -106,3 +106,5 @@ remote deployments. It redacts its owned management token and common bearer/toke
106
106
  query forms, but cannot guarantee redaction of arbitrary plugin output.
107
107
 
108
108
  For release validation and Trusted Publisher setup, see [releasing](docs/releasing.md).
109
+
110
+ For development hooks and contribution rules, see [Contributing](CONTRIBUTING.md).
@@ -3,7 +3,7 @@
3
3
  Toolframe testkit is a Python library for checking a plugin's public SDK contract
4
4
  and exercising an installed Toolframe Core application through its public CLI and
5
5
  HTTP APIs. It is a developer test dependency, not a Core runtime plugin. Version
6
- 0.1.2 supports Python 3.14 or newer and pins `toolframe-sdk==0.3.0`.
6
+ 0.2.0 supports Python 3.14 or newer and pins `toolframe-sdk==0.4.0`.
7
7
 
8
8
  The package is Apache-2.0 licensed. It does not install Core, choose a global
9
9
  application, or load a pytest plugin automatically.
@@ -13,7 +13,7 @@ application, or load a pytest plugin automatically.
13
13
  Install the checker and opt-in pytest integration from PyPI:
14
14
 
15
15
  ```sh
16
- python -m pip install 'toolframe-testkit[pytest]==0.1.2'
16
+ python -m pip install 'toolframe-testkit[pytest]==0.2.0'
17
17
  ```
18
18
 
19
19
  The SDK is installed as a dependency. See
@@ -84,3 +84,5 @@ remote deployments. It redacts its owned management token and common bearer/toke
84
84
  query forms, but cannot guarantee redaction of arbitrary plugin output.
85
85
 
86
86
  For release validation and Trusted Publisher setup, see [releasing](docs/releasing.md).
87
+
88
+ For development hooks and contribution rules, see [Contributing](CONTRIBUTING.md).
@@ -0,0 +1,10 @@
1
+ [commit]
2
+ conventional_commits = true
3
+ allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "perf", "build", "ci"]
4
+
5
+ [branch]
6
+ conventional_branch = true
7
+ allow_branch_types = ["feat", "fix", "release", "chore"]
8
+ allow_branch_names = ["main"]
9
+ # scripts/check_branch_name.py enforces these names literally, without the
10
+ # additional standalone branch exceptions built into commit-check.
@@ -1,10 +1,9 @@
1
1
  # Development and verification
2
2
 
3
3
  The testkit repository is independently buildable. Runtime dependencies are
4
- `toolframe-sdk==0.3.0`, `httpx`, `tomlkit`, `psutil`, `pydantic`, and `jsonschema`;
4
+ `toolframe-sdk==0.4.0`, `httpx`, `tomlkit`, `psutil`, `pydantic`, and `jsonschema`;
5
5
  pytest is available
6
- through the `[pytest]` extra. Python 3.14 or newer is required. No release is
7
- published yet, so consumer-style installation uses a local wheelhouse.
6
+ through the `[pytest]` extra. Python 3.14 or newer is required. Consumer-style installation can use PyPI or an explicitly built local wheelhouse.
8
7
 
9
8
  ## Local environment
10
9
 
@@ -13,7 +12,7 @@ install the package with the development tools. The install must use the
13
12
  wheelhouse so uv does not select an unrelated source checkout:
14
13
 
15
14
  ```sh
16
- mkdir -p .local/wheelhouse
15
+ mkdir -p build/wheelhouse
17
16
  ```
18
17
 
19
18
  When testing sibling development checkouts, build their wheels into a local,
@@ -21,15 +20,15 @@ ignored wheelhouse. These commands are for a sibling checkout layout and are
21
20
  deliberately explicit about `--no-sources`:
22
21
 
23
22
  ```sh
24
- uv build --no-sources --wheel --out-dir .local/wheelhouse \
23
+ uv build --no-sources --wheel --out-dir build/wheelhouse \
25
24
  ../toolframe-sdk/.worktrees/plugin-services
26
- uv build --no-sources --wheel --out-dir .local/wheelhouse \
25
+ uv build --no-sources --wheel --out-dir build/wheelhouse \
27
26
  ../fastapi-cordis
28
- uv build --no-sources --wheel --out-dir .local/wheelhouse \
29
- ../toolframe-core/.worktrees/plugin-services
30
- uv build --no-sources --wheel --out-dir .local/wheelhouse \
31
- ../toolframe-storage-sqlite
32
- uv build --no-sources --wheel --out-dir .local/wheelhouse \
27
+ uv build --no-sources --wheel --out-dir build/wheelhouse \
28
+ ../toolframe-core
29
+ uv build --no-sources --wheel --out-dir build/wheelhouse \
30
+ ../toolframe-sql-sqlite
31
+ uv build --no-sources --wheel --out-dir build/wheelhouse \
33
32
  tests/assets/service-plugin
34
33
  ```
35
34
 
@@ -39,7 +38,7 @@ SDK wheel, install the development environment:
39
38
 
40
39
  ```sh
41
40
  uv venv .venv
42
- uv pip install --python .venv/bin/python --find-links .local/wheelhouse \
41
+ uv pip install --python .venv/bin/python --find-links build/wheelhouse \
43
42
  -e '.[pytest]' pytest ruff build hatchling
44
43
  ```
45
44
 
@@ -71,16 +70,16 @@ Install the matching Core command into the same environment after its Core,
71
70
  Cordis, and SDK wheels are in the wheelhouse:
72
71
 
73
72
  ```sh
74
- uv pip install --python .venv/bin/python --find-links .local/wheelhouse \
75
- toolframe-core==0.6.2
73
+ uv pip install --python .venv/bin/python --find-links build/wheelhouse \
74
+ toolframe-core==0.7.0
76
75
  ```
77
76
 
78
77
  ```sh
79
- export TOOLFRAME_TESTKIT_STORAGE_WHEEL="$PWD/.local/wheelhouse/toolframe_storage_sqlite-0.3.0-py3-none-any.whl"
80
- export TOOLFRAME_TESTKIT_FIXTURE_WHEEL="$PWD/.local/wheelhouse/toolframe_testkit_fixture-0.1.0-py3-none-any.whl"
78
+ export TOOLFRAME_TESTKIT_STORAGE_WHEEL="$PWD/build/wheelhouse/toolframe_sql_sqlite-0.4.0-py3-none-any.whl"
79
+ export TOOLFRAME_TESTKIT_FIXTURE_WHEEL="$PWD/build/wheelhouse/toolframe_testkit_fixture-0.1.0-py3-none-any.whl"
81
80
  .venv/bin/python -m pytest tests/test_installed_core.py \
82
81
  --toolframe-core-command "$PWD/.venv/bin/toolframe-core" \
83
- --toolframe-find-links "$PWD/.local/wheelhouse" \
82
+ --toolframe-find-links "$PWD/build/wheelhouse" \
84
83
  --toolframe-output-directory build/installed-core
85
84
  ```
86
85
 
@@ -104,8 +103,8 @@ find-links directory, and output directory:
104
103
  ```sh
105
104
  .venv/bin/python scripts/smoke_wheel.py \
106
105
  --wheel dist/toolframe_testkit-0.1.2-py3-none-any.whl \
107
- --fixture-wheel .local/wheelhouse/toolframe_testkit_fixture-0.1.0-py3-none-any.whl \
108
- --find-links .local/wheelhouse \
106
+ --fixture-wheel build/wheelhouse/toolframe_testkit_fixture-0.1.0-py3-none-any.whl \
107
+ --find-links build/wheelhouse \
109
108
  --output build/wheel-smoke
110
109
  ```
111
110
 
@@ -14,9 +14,9 @@ from toolframe_testkit import ApplicationHarness
14
14
  with ApplicationHarness(
15
15
  "/path/to/toolframe-core",
16
16
  output_directory=Path("build/installed-core"),
17
- find_links=[Path(".local/wheelhouse")],
17
+ find_links=[Path("build/wheelhouse")],
18
18
  ) as app:
19
- app.install_plugin(".local/wheelhouse/my_plugin-0.1.0-py3-none-any.whl")
19
+ app.install_plugin("build/wheelhouse/my_plugin-0.1.0-py3-none-any.whl")
20
20
  app.wait_for_plugin("my-plugin")
21
21
  response = app.service_call(
22
22
  "my-plugin", "my.records", "list", {}, entrance="public"
@@ -19,7 +19,7 @@ metadata and licenses, runs Ruff and package tests against an installed wheel,
19
19
  and installs each distribution into a separate fresh consumer environment.
20
20
  Optional database/service integrations require their documented fixtures.
21
21
 
22
- Publish `toolframe-sdk==0.3.0` first. The pytest extra is installed with `toolframe-testkit[pytest]`. The coordinated order and native CLI channels are documented in
22
+ Publish `toolframe-sdk==0.4.0` first. The pytest extra is installed with `toolframe-testkit[pytest]`. The coordinated order and native CLI channels are documented in
23
23
  [Toolframe's release guide](https://github.com/toolframe/toolframe-core/blob/main/docs/releasing.md).
24
24
 
25
25
  ## Trusted Publishers
@@ -58,7 +58,7 @@ After PyPI publication, verify a clean installation:
58
58
 
59
59
  ```sh
60
60
  uv venv --python 3.14.7 build/consumer
61
- uv pip install --python build/consumer/bin/python 'toolframe-testkit==0.1.2'
61
+ uv pip install --python build/consumer/bin/python 'toolframe-testkit==0.2.0'
62
62
  uv pip check --python build/consumer/bin/python
63
63
  ```
64
64
 
@@ -5,7 +5,7 @@ Example::
5
5
  python examples/installed_application.py \
6
6
  --core-command /path/to/toolframe-core \
7
7
  --wheelhouse .local/wheelhouse \
8
- --storage-wheel /tmp/toolframe_storage_sqlite.whl \
8
+ --storage-wheel /tmp/toolframe_sql_sqlite.whl \
9
9
  --fixture-wheel /tmp/toolframe_testkit_fixture.whl \
10
10
  --output build/installed-application
11
11
 
@@ -21,7 +21,7 @@ from pathlib import Path
21
21
 
22
22
  from toolframe_testkit import ApplicationHarness
23
23
 
24
- _STORAGE_PLUGIN = "storage-sqlite"
24
+ _STORAGE_PLUGIN = "sql-sqlite"
25
25
  _FIXTURE_PLUGIN = "fixture-records"
26
26
  _SERVICE = "fixture-records.records"
27
27
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "toolframe-testkit"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Public contract checks and installed-application tests for Toolframe developers"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -12,7 +12,7 @@ license-files = ["LICENSE"]
12
12
  authors = [{ name = "byfb", email = "62798989+byfb@users.noreply.github.com" }]
13
13
  requires-python = ">=3.14"
14
14
  dependencies = [
15
- "toolframe-sdk==0.3.0", "httpx>=0.28,<1", "tomlkit>=0.13,<1", "psutil>=7,<9",
15
+ "toolframe-sdk==0.4.0", "httpx>=0.28,<1", "tomlkit>=0.13,<1", "psutil>=7,<9",
16
16
  "jsonschema>=4.23,<5", "pydantic>=2.12.5,<3",
17
17
  ]
18
18
 
@@ -0,0 +1,59 @@
1
+ """Validate a working branch using the repository's cchk.toml policy."""
2
+
3
+ import argparse
4
+ import re
5
+ import subprocess
6
+ import sys
7
+ import tomllib
8
+ from pathlib import Path
9
+
10
+
11
+ def main() -> int:
12
+ parser = argparse.ArgumentParser(description=__doc__)
13
+ parser.add_argument("branch", nargs="?", help="actual source branch in CI")
14
+ args = parser.parse_args()
15
+ root = Path(__file__).resolve().parent.parent
16
+ policy = tomllib.loads((root / "cchk.toml").read_text())["branch"]
17
+ branch = args.branch
18
+ if branch is None:
19
+ result = subprocess.run(
20
+ ["git", "symbolic-ref", "--quiet", "--short", "HEAD"],
21
+ cwd=root,
22
+ capture_output=True,
23
+ text=True,
24
+ check=False,
25
+ )
26
+ if result.returncode:
27
+ print(
28
+ "Pass the actual source branch when HEAD is detached.", file=sys.stderr
29
+ )
30
+ return 1
31
+ branch = result.stdout.strip()
32
+
33
+ if branch in policy["allow_branch_names"]:
34
+ return 0
35
+ prefix, separator, description = branch.partition("/")
36
+ pattern = (
37
+ r"[a-z0-9]+(?:[.-][a-z0-9]+)*"
38
+ if prefix == "release"
39
+ else r"[a-z0-9]+(?:-[a-z0-9]+)*"
40
+ )
41
+ if (
42
+ separator
43
+ and prefix in policy["allow_branch_types"]
44
+ and re.fullmatch(pattern, description)
45
+ ):
46
+ return 0
47
+
48
+ allowed = ", ".join(policy["allow_branch_types"])
49
+ print(
50
+ f"Invalid branch {branch!r}. Use <type>/<description> with type: {allowed}. "
51
+ "Use lowercase letters and digits separated by single hyphens; "
52
+ "release versions may also contain dots.",
53
+ file=sys.stderr,
54
+ )
55
+ return 1
56
+
57
+
58
+ if __name__ == "__main__":
59
+ raise SystemExit(main())
@@ -66,7 +66,7 @@ def main():
66
66
  assert document["Requires-Python"] == ">=3.14"
67
67
  assert document["License-Expression"] == "Apache-2.0"
68
68
  requirements = document.get_all("Requires-Dist") or []
69
- assert any(item.startswith("toolframe-sdk==0.3.0") for item in requirements)
69
+ assert any(item.startswith("toolframe-sdk==0.4.0") for item in requirements)
70
70
  assert not any(" @ " in item or "file:" in item for item in requirements)
71
71
  assert not any(
72
72
  "fixture_records/" in name or name.startswith("tests/") for name in names
@@ -10,7 +10,7 @@ from .contracts import (
10
10
  )
11
11
  from .harness import ApplicationHarness, CLIResult, HarnessError, HarnessTimeout
12
12
 
13
- __version__ = "0.1.2"
13
+ __version__ = "0.2.0"
14
14
  __all__ = [
15
15
  "ApplicationHarness",
16
16
  "CLIResult",
@@ -9,7 +9,7 @@ description = "Small independently packaged Toolframe records plugin for testkit
9
9
  license = "Apache-2.0"
10
10
  license-files = ["LICENSE"]
11
11
  requires-python = ">=3.14"
12
- dependencies = ["toolframe-sdk==0.3.0"]
12
+ dependencies = ["toolframe-sdk==0.4.0"]
13
13
 
14
14
  [project.entry-points."toolframe.plugins"]
15
15
  fixture-records = "fixture_records.definition:plugin"
@@ -87,7 +87,7 @@ plugin = PluginDefinition(
87
87
  "fixture-records.write": ScopeSpec(title="Append fixture records"),
88
88
  }
89
89
  ),
90
- requires={"storage": Requirement(service="toolframe.storage.sql")},
90
+ requires={"sql": Requirement(service="toolframe.sql")},
91
91
  services={
92
92
  SERVICE: ServiceSpec(
93
93
  methods={
@@ -32,7 +32,7 @@ class Records(Plugin):
32
32
 
33
33
  async def append(self, body: object) -> dict:
34
34
  body = _validate_body(body)
35
- storage = self.context.storage()
35
+ storage = self.context.sql()
36
36
  async with storage.transaction() as transaction:
37
37
  result = await transaction.execute_returning(
38
38
  "INSERT INTO records(body) VALUES (?) RETURNING id",
@@ -62,7 +62,7 @@ class Records(Plugin):
62
62
 
63
63
  async def list_records(self, limit: object = 20) -> dict:
64
64
  limit = _validate_limit(limit)
65
- records = await self.context.storage().query(
65
+ records = await self.context.sql().query(
66
66
  "SELECT id, body FROM records ORDER BY id DESC LIMIT ?",
67
67
  (limit,),
68
68
  )
@@ -90,5 +90,5 @@ class Records(Plugin):
90
90
  raise PluginError("method_not_found", f"Unknown method {service}/{method}")
91
91
 
92
92
  async def health(self) -> dict:
93
- await self.context.storage().query("SELECT id FROM records LIMIT 1")
93
+ await self.context.sql().query("SELECT id FROM records LIMIT 1")
94
94
  return {"runtime": "ready", "business": "ready"}
@@ -17,7 +17,7 @@ pytestmark = pytest.mark.installed_core
17
17
 
18
18
  _STORAGE_WHEEL_ENV = "TOOLFRAME_TESTKIT_STORAGE_WHEEL"
19
19
  _FIXTURE_WHEEL_ENV = "TOOLFRAME_TESTKIT_FIXTURE_WHEEL"
20
- _STORAGE_PLUGIN = "storage-sqlite"
20
+ _STORAGE_PLUGIN = "sql-sqlite"
21
21
  _FIXTURE_PLUGIN = "fixture-records"
22
22
  _SERVICE = "fixture-records.records"
23
23
 
@@ -448,7 +448,7 @@ wheels = [
448
448
 
449
449
  [[package]]
450
450
  name = "toolframe-sdk"
451
- version = "0.3.0"
451
+ version = "0.4.0"
452
452
  source = { editable = "../toolframe-sdk" }
453
453
  dependencies = [
454
454
  { name = "jsonschema" },
@@ -475,7 +475,7 @@ dev = [
475
475
 
476
476
  [[package]]
477
477
  name = "toolframe-testkit"
478
- version = "0.1.2"
478
+ version = "0.2.0"
479
479
  source = { editable = "." }
480
480
  dependencies = [
481
481
  { name = "httpx" },