strictcli 0.12.0__tar.gz → 0.14.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.
- strictcli-0.14.0/.github/workflows/publish.yml +27 -0
- strictcli-0.14.0/.npmignore +34 -0
- strictcli-0.14.0/.rlsbl/bases/.github/workflows/publish.yml +27 -0
- strictcli-0.14.0/.rlsbl/bases/.npmignore +34 -0
- strictcli-0.14.0/.rlsbl/changes/.validated +1 -0
- strictcli-0.14.0/.rlsbl/changes/0.13.0.jsonl +3 -0
- strictcli-0.14.0/.rlsbl/changes/0.13.0.md +5 -0
- strictcli-0.14.0/.rlsbl/changes/0.14.0.jsonl +3 -0
- strictcli-0.14.0/.rlsbl/changes/0.14.0.md +5 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/hashes.json +3 -2
- strictcli-0.14.0/.rlsbl/releases/v0.13.0.toml +4 -0
- strictcli-0.14.0/.rlsbl/version +1 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/CHANGELOG.md +21 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/PKG-INFO +1 -1
- {strictcli-0.12.0 → strictcli-0.14.0}/package-lock.json +2 -2
- {strictcli-0.12.0 → strictcli-0.14.0}/package.json +1 -1
- {strictcli-0.12.0 → strictcli-0.14.0}/pyproject.toml +1 -1
- {strictcli-0.12.0 → strictcli-0.14.0}/strictcli/__init__.py +68 -19
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_check_discovery.py +51 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_check_schema.py +7 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_dump_schema.py +66 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/uv.lock +1 -1
- strictcli-0.12.0/.github/workflows/publish.yml +0 -32
- strictcli-0.12.0/.rlsbl/bases/.github/workflows/publish.yml +0 -32
- strictcli-0.12.0/.rlsbl/changes/.validated +0 -1
- strictcli-0.12.0/.rlsbl/releases/unreleased.toml +0 -0
- strictcli-0.12.0/.rlsbl/version +0 -1
- {strictcli-0.12.0 → strictcli-0.14.0}/.claude/settings.json +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.github/workflows/ci.yml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.gitignore +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.claude/settings.json +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.github/workflows/ci.yml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.gitignore +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/hooks/post-release.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/lint/go.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/lint/npm.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/.rlsbl/lint/python.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/CHANGELOG.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/CLAUDE.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/bases/LICENSE +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.10.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.10.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.11.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.11.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.12.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.12.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.4.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.4.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.4.1.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.4.1.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.5.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.5.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.6.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.6.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.6.1.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.6.1.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.7.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.7.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.7.1.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.7.1.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.1.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.1.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.2.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.2.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.3.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.3.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.4.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.4.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.5.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.5.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.6.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.6.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.7.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.8.7.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.9.0.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.9.0.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.9.1.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/0.9.1.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/changes/unreleased.jsonl +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/config.json +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/hooks/post-release.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/hooks/pre-checks.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/hooks/pre-release.sh +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/lint/go.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/lint/npm.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/lint/python.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.10.0.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.11.0.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.12.0.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.8.5.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.8.6.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.8.7.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.9.0.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.rlsbl/releases/v0.9.1.toml +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/.strictcli/schema.json +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/CLAUDE.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/LICENSE +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/README.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/index.js +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/postinstall.js +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_arg_default.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_at_prefix.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_auto_version.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_check_command.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_check_runner.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_check_types.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_choices.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_command_help_suggestion.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_config.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_config_file_path.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_deep_nesting.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_dependencies.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_deprecated.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_e2e.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_env.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_exit_codes.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_float_type.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_global_flags.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_help.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_int_type.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_mutex.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_nesting.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_parser.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_passthrough.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_registration.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_repeatable.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_tagdsl.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_tags.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_toml_loading.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_validate.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/tests/test_variadic.py +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/todo/.defer/deferred.md +0 -0
- {strictcli-0.12.0 → strictcli-0.14.0}/todo/.done/original-idea.md +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
id-token: write
|
|
9
|
+
jobs:
|
|
10
|
+
pypi:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
- uses: astral-sh/setup-uv@v7
|
|
15
|
+
- run: uv build
|
|
16
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
17
|
+
npm:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- uses: actions/setup-node@v6
|
|
22
|
+
with:
|
|
23
|
+
node-version: 24
|
|
24
|
+
registry-url: https://registry.npmjs.org
|
|
25
|
+
- run: npm publish --provenance --access public
|
|
26
|
+
env:
|
|
27
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Development and CI
|
|
2
|
+
tests/
|
|
3
|
+
test/
|
|
4
|
+
__tests__/
|
|
5
|
+
.github/
|
|
6
|
+
scripts/
|
|
7
|
+
docs/
|
|
8
|
+
todo/
|
|
9
|
+
e2e/
|
|
10
|
+
|
|
11
|
+
# rlsbl metadata
|
|
12
|
+
.rlsbl/
|
|
13
|
+
.rlsbl-monorepo/
|
|
14
|
+
|
|
15
|
+
# Python artifacts (for multi-target projects)
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.pyc
|
|
18
|
+
*.py
|
|
19
|
+
*.toml
|
|
20
|
+
.venv/
|
|
21
|
+
|
|
22
|
+
# Build/cache
|
|
23
|
+
coverage/
|
|
24
|
+
.nyc_output/
|
|
25
|
+
|
|
26
|
+
# Editor/OS
|
|
27
|
+
.DS_Store
|
|
28
|
+
*.log
|
|
29
|
+
.env
|
|
30
|
+
.env.local
|
|
31
|
+
|
|
32
|
+
# Selfdoc
|
|
33
|
+
.selfdoc/
|
|
34
|
+
selfdoc.json
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
id-token: write
|
|
9
|
+
jobs:
|
|
10
|
+
pypi:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
- uses: astral-sh/setup-uv@v7
|
|
15
|
+
- run: uv build
|
|
16
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
17
|
+
npm:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- uses: actions/setup-node@v6
|
|
22
|
+
with:
|
|
23
|
+
node-version: 24
|
|
24
|
+
registry-url: https://registry.npmjs.org
|
|
25
|
+
- run: npm publish --provenance --access public
|
|
26
|
+
env:
|
|
27
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Development and CI
|
|
2
|
+
tests/
|
|
3
|
+
test/
|
|
4
|
+
__tests__/
|
|
5
|
+
.github/
|
|
6
|
+
scripts/
|
|
7
|
+
docs/
|
|
8
|
+
todo/
|
|
9
|
+
e2e/
|
|
10
|
+
|
|
11
|
+
# rlsbl metadata
|
|
12
|
+
.rlsbl/
|
|
13
|
+
.rlsbl-monorepo/
|
|
14
|
+
|
|
15
|
+
# Python artifacts (for multi-target projects)
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.pyc
|
|
18
|
+
*.py
|
|
19
|
+
*.toml
|
|
20
|
+
.venv/
|
|
21
|
+
|
|
22
|
+
# Build/cache
|
|
23
|
+
coverage/
|
|
24
|
+
.nyc_output/
|
|
25
|
+
|
|
26
|
+
# Editor/OS
|
|
27
|
+
.DS_Store
|
|
28
|
+
*.log
|
|
29
|
+
.env
|
|
30
|
+
.env.local
|
|
31
|
+
|
|
32
|
+
# Selfdoc
|
|
33
|
+
.selfdoc/
|
|
34
|
+
selfdoc.json
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
caba81b23948f3b79c908ccd06ed76596881c075
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{"commits":["12ad7c022938b07cf1f44b20bdbe9de0ae6a84be"],"user_facing":true,"description":"**New feature.** Schema dump (--dump-schema) now includes a project_id field read from pyproject.toml, providing provenance for schema validation.","type":"feature"}
|
|
2
|
+
{"commits":["a50cf7899c938974b12e8e74201bdf58c0205a55"],"user_facing":false}
|
|
3
|
+
{"commits":["214721745a82a47189a13b2443fb9ddc59826347"],"user_facing":false}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{"commits":["f2f2de83edc0b7fe24f46744201e8be1407f28a3"],"user_facing":false}
|
|
2
|
+
{"commits":["a2e1d64fb5f695169fafa63e5d1b69fe5c4e043d"],"user_facing":true,"description":"**New feature.** `checks_embed` parameter accepts raw TOML bytes, enabling inline checks configuration without a file on disk.","type":"feature"}
|
|
3
|
+
{"commits":["09799755dc2ef93a088f739a46001102bcb2aa5e"],"user_facing":false}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
".github/workflows/ci.yml": "b4e075171b131d25f9cce55a3e3a30732e95a2a794af00f354ee3200626d6a04",
|
|
3
|
-
".github/workflows/publish.yml": "
|
|
3
|
+
".github/workflows/publish.yml": "e77dcd0b5d1c1abae5424e5f3b73862f44f06b5d46209cbe71bc04d6baa6b5be",
|
|
4
4
|
"CHANGELOG.md": "7a6ec46141007c18090a0ff325e2dd68cd51588c4e0b5af7b580365e5eaaca85",
|
|
5
5
|
".gitignore": "c89d76c6c43e7f0897b3472a15b7c0103e0be5b3a04c2b44e585fa48bdcda2bb",
|
|
6
6
|
"LICENSE": "e958892abc1dd5d991fca6d528e695d335f25773d373d2e0be5f4a9507d8f8d5",
|
|
@@ -11,5 +11,6 @@
|
|
|
11
11
|
".rlsbl/hooks/pre-checks.sh": "60c57d4563263124530e6f33aca77550ea2161ad3b33b3ba6ad1c03fea9eb6e2",
|
|
12
12
|
".rlsbl/lint/python.toml": "9cfbcef2e010d5fad243437bf2fd8df54a1fae70ee0762f9d11da70fe207501c",
|
|
13
13
|
".rlsbl/lint/go.toml": "807d5cf760baad6d571a5bfd43cb163efe356f7462ba9f1918d72de45f62339f",
|
|
14
|
-
".rlsbl/lint/npm.toml": "baa36014e65923d8cc5c8b83c77fa651da79351627570476402da66840027645"
|
|
14
|
+
".rlsbl/lint/npm.toml": "baa36014e65923d8cc5c8b83c77fa651da79351627570476402da66840027645",
|
|
15
|
+
".npmignore": "7c0eea9785c0318aeb39bf8b670ce8384f4a5b812fde69ce23d7d018057325a3"
|
|
15
16
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.60.1
|
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## 0.14.0
|
|
6
|
+
|
|
7
|
+
checks_embed for inline TOML data
|
|
8
|
+
|
|
9
|
+
<details>
|
|
10
|
+
<summary>Context</summary>
|
|
11
|
+
|
|
12
|
+
Adds checks_embed parameter as an alternative to checks_path, allowing TOML bytes to be passed directly without requiring a file on disk.
|
|
13
|
+
|
|
14
|
+
</details>
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **New feature.** `checks_embed` parameter accepts raw TOML bytes, enabling inline checks configuration without a file on disk.
|
|
19
|
+
|
|
20
|
+
## 0.13.0
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
- **New feature.** Schema dump (--dump-schema) now includes a project_id field read from pyproject.toml, providing provenance for schema validation.
|
|
25
|
+
|
|
5
26
|
## 0.12.0
|
|
6
27
|
|
|
7
28
|
### Breaking
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strictcli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "strictcli",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.14.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT"
|
|
12
12
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__version__ = "0.
|
|
5
|
+
__version__ = "0.14.0"
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"App", "Flag", "Arg", "Tag", "MutexGroup", "CoRequired", "Requires",
|
|
@@ -130,37 +130,32 @@ _CHECK_REQUIRED_FIELDS = {"tags", "severity", "fast", "pure", "needs_network", "
|
|
|
130
130
|
_CHECK_VALID_SEVERITIES = {"error", "warn"}
|
|
131
131
|
|
|
132
132
|
|
|
133
|
-
def
|
|
134
|
-
"""Parse and validate
|
|
133
|
+
def _parse_checks_toml(data: bytes) -> tuple[str, dict[str, _CheckDef]]:
|
|
134
|
+
"""Parse and validate checks TOML data, returning (app_name, check_defs).
|
|
135
135
|
|
|
136
|
-
Raises ValueError on any schema violation
|
|
136
|
+
Raises ValueError on any schema violation or invalid TOML.
|
|
137
137
|
"""
|
|
138
|
-
path = Path(path)
|
|
139
|
-
try:
|
|
140
|
-
raw = path.read_bytes()
|
|
141
|
-
except OSError as exc:
|
|
142
|
-
raise ValueError(f"checks.toml: {exc}") from exc
|
|
143
138
|
try:
|
|
144
|
-
|
|
139
|
+
parsed = tomllib.loads(data.decode())
|
|
145
140
|
except (tomllib.TOMLDecodeError, UnicodeDecodeError) as exc:
|
|
146
141
|
raise ValueError(f"checks.toml: {exc}") from exc
|
|
147
142
|
|
|
148
143
|
# Only "app" and [checks] are allowed at the top level
|
|
149
|
-
for key in
|
|
144
|
+
for key in parsed:
|
|
150
145
|
if key not in ("app", "checks"):
|
|
151
146
|
raise ValueError(f'checks.toml: unknown top-level key "{key}"')
|
|
152
147
|
|
|
153
148
|
# Validate required "app" field
|
|
154
|
-
if "app" not in
|
|
149
|
+
if "app" not in parsed:
|
|
155
150
|
raise ValueError('checks.toml: missing required top-level key "app"')
|
|
156
|
-
if not isinstance(
|
|
151
|
+
if not isinstance(parsed["app"], str) or not parsed["app"]:
|
|
157
152
|
raise ValueError('checks.toml: "app" must be a non-empty string')
|
|
158
|
-
app_name =
|
|
153
|
+
app_name = parsed["app"]
|
|
159
154
|
|
|
160
|
-
if "checks" not in
|
|
155
|
+
if "checks" not in parsed:
|
|
161
156
|
return (app_name, {})
|
|
162
157
|
|
|
163
|
-
checks_section =
|
|
158
|
+
checks_section = parsed["checks"]
|
|
164
159
|
if not isinstance(checks_section, dict):
|
|
165
160
|
raise ValueError("checks.toml: [checks] must be a table")
|
|
166
161
|
|
|
@@ -253,6 +248,19 @@ def _load_checks_toml(path: str | Path) -> tuple[str, dict[str, _CheckDef]]:
|
|
|
253
248
|
return (app_name, result)
|
|
254
249
|
|
|
255
250
|
|
|
251
|
+
def _load_checks_toml(path: str | Path) -> tuple[str, dict[str, _CheckDef]]:
|
|
252
|
+
"""Read and parse a checks.toml file, returning (app_name, check_defs).
|
|
253
|
+
|
|
254
|
+
Raises ValueError on any file error, schema violation, or invalid TOML.
|
|
255
|
+
"""
|
|
256
|
+
path = Path(path)
|
|
257
|
+
try:
|
|
258
|
+
raw = path.read_bytes()
|
|
259
|
+
except OSError as exc:
|
|
260
|
+
raise ValueError(f"checks.toml: {exc}") from exc
|
|
261
|
+
return _parse_checks_toml(raw)
|
|
262
|
+
|
|
263
|
+
|
|
256
264
|
class _HelpRequested(Exception):
|
|
257
265
|
"""Raised when --help or -h is encountered."""
|
|
258
266
|
|
|
@@ -675,6 +683,7 @@ class App:
|
|
|
675
683
|
config_path: str | None = None
|
|
676
684
|
config_format: str = "json"
|
|
677
685
|
checks_path: str | Path | None = None
|
|
686
|
+
checks_embed: bytes | None = None
|
|
678
687
|
flags: list[Flag] = field(default_factory=list)
|
|
679
688
|
_commands: dict[str, Command] = field(default_factory=dict)
|
|
680
689
|
_groups: dict[str, Group] = field(default_factory=dict)
|
|
@@ -712,6 +721,8 @@ class App:
|
|
|
712
721
|
self._register_config_group()
|
|
713
722
|
# Discover checks TOML
|
|
714
723
|
self._check_context_factory: Callable | None = None
|
|
724
|
+
if self.checks_path is not None and self.checks_embed is not None:
|
|
725
|
+
raise ValueError("cannot use both checks_path and checks_embed")
|
|
715
726
|
if self.checks_path is not None:
|
|
716
727
|
checks_toml_path = Path(self.checks_path).resolve()
|
|
717
728
|
if not checks_toml_path.is_file():
|
|
@@ -723,6 +734,14 @@ class App:
|
|
|
723
734
|
)
|
|
724
735
|
self._checks_enabled = True
|
|
725
736
|
self._register_check_command()
|
|
737
|
+
elif self.checks_embed is not None:
|
|
738
|
+
app_name, self._check_defs = _parse_checks_toml(self.checks_embed)
|
|
739
|
+
if app_name != self.name:
|
|
740
|
+
raise ValueError(
|
|
741
|
+
f'checks.toml: app "{app_name}" does not match app name "{self.name}"'
|
|
742
|
+
)
|
|
743
|
+
self._checks_enabled = True
|
|
744
|
+
self._register_check_command()
|
|
726
745
|
else:
|
|
727
746
|
self._check_defs: dict[str, _CheckDef] = {}
|
|
728
747
|
self._checks_enabled = False
|
|
@@ -1460,7 +1479,11 @@ class App:
|
|
|
1460
1479
|
print(_format_version(self))
|
|
1461
1480
|
sys.exit(0)
|
|
1462
1481
|
except _DumpSchemaRequested:
|
|
1463
|
-
|
|
1482
|
+
try:
|
|
1483
|
+
path = _write_schema(self)
|
|
1484
|
+
except RuntimeError as e:
|
|
1485
|
+
print(f"error: {e}", file=sys.stderr)
|
|
1486
|
+
sys.exit(1)
|
|
1464
1487
|
print(path)
|
|
1465
1488
|
sys.exit(0)
|
|
1466
1489
|
except _ParseError as e:
|
|
@@ -1503,8 +1526,13 @@ class App:
|
|
|
1503
1526
|
except _VersionRequested:
|
|
1504
1527
|
stdout_buf.write(_format_version(self) + "\n")
|
|
1505
1528
|
except _DumpSchemaRequested:
|
|
1506
|
-
|
|
1507
|
-
|
|
1529
|
+
try:
|
|
1530
|
+
path = _write_schema(self)
|
|
1531
|
+
except RuntimeError as e:
|
|
1532
|
+
stderr_buf.write(f"error: {e}\n")
|
|
1533
|
+
exit_code = 1
|
|
1534
|
+
else:
|
|
1535
|
+
stdout_buf.write(path + "\n")
|
|
1508
1536
|
except _ParseError as e:
|
|
1509
1537
|
stderr_buf.write(f"error: {e}\n")
|
|
1510
1538
|
prefix = e.command_prefix or self.name
|
|
@@ -3087,14 +3115,35 @@ def _build_schema_defaults() -> dict:
|
|
|
3087
3115
|
}
|
|
3088
3116
|
|
|
3089
3117
|
|
|
3118
|
+
def _read_project_id() -> str:
|
|
3119
|
+
"""Read project name from pyproject.toml in the current working directory."""
|
|
3120
|
+
pyproject_path = Path(os.getcwd()) / "pyproject.toml"
|
|
3121
|
+
if not pyproject_path.exists():
|
|
3122
|
+
raise RuntimeError(
|
|
3123
|
+
"Cannot determine project_id: pyproject.toml not found "
|
|
3124
|
+
"or missing [project].name"
|
|
3125
|
+
)
|
|
3126
|
+
with open(pyproject_path, "rb") as f:
|
|
3127
|
+
data = tomllib.load(f)
|
|
3128
|
+
project_name = data.get("project", {}).get("name")
|
|
3129
|
+
if not project_name:
|
|
3130
|
+
raise RuntimeError(
|
|
3131
|
+
"Cannot determine project_id: pyproject.toml not found "
|
|
3132
|
+
"or missing [project].name"
|
|
3133
|
+
)
|
|
3134
|
+
return project_name
|
|
3135
|
+
|
|
3136
|
+
|
|
3090
3137
|
def _dump_schema(app: App) -> dict:
|
|
3091
3138
|
"""Produce a JSON-serializable dict representing the app's command tree.
|
|
3092
3139
|
|
|
3093
3140
|
Fields whose values match the schema defaults are omitted.
|
|
3094
3141
|
The top-level ``defaults`` key documents what each missing field means.
|
|
3095
3142
|
"""
|
|
3143
|
+
project_id = _read_project_id()
|
|
3096
3144
|
schema: dict = {
|
|
3097
3145
|
"defaults": _build_schema_defaults(),
|
|
3146
|
+
"project_id": project_id,
|
|
3098
3147
|
"name": app.name,
|
|
3099
3148
|
"version": app.version,
|
|
3100
3149
|
"help": app.help,
|
|
@@ -293,3 +293,54 @@ depends_on = []
|
|
|
293
293
|
name="testapp", version="1.0.0", help="test app",
|
|
294
294
|
checks_path=str(toml_file),
|
|
295
295
|
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class TestChecksEmbed:
|
|
299
|
+
def test_checks_embed_enables_checks(self, tmp_path, monkeypatch):
|
|
300
|
+
"""checks_embed with valid TOML bytes enables checks."""
|
|
301
|
+
monkeypatch.chdir(tmp_path)
|
|
302
|
+
|
|
303
|
+
app = strictcli.App(
|
|
304
|
+
name="testapp", version="1.0.0", help="test app",
|
|
305
|
+
checks_embed=VALID_TOML.encode(),
|
|
306
|
+
)
|
|
307
|
+
assert app._checks_enabled is True
|
|
308
|
+
assert "lint-code" in app._check_defs
|
|
309
|
+
assert "check-deps" in app._check_defs
|
|
310
|
+
|
|
311
|
+
def test_checks_embed_and_checks_path_raises(self, tmp_path, monkeypatch):
|
|
312
|
+
"""Using both checks_path and checks_embed raises ValueError."""
|
|
313
|
+
monkeypatch.chdir(tmp_path)
|
|
314
|
+
toml_file = tmp_path / "checks.toml"
|
|
315
|
+
toml_file.write_text(VALID_TOML)
|
|
316
|
+
|
|
317
|
+
with pytest.raises(ValueError, match="cannot use both checks_path and checks_embed"):
|
|
318
|
+
strictcli.App(
|
|
319
|
+
name="testapp", version="1.0.0", help="test app",
|
|
320
|
+
checks_path=str(toml_file),
|
|
321
|
+
checks_embed=VALID_TOML.encode(),
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
def test_checks_embed_invalid_toml(self, tmp_path, monkeypatch):
|
|
325
|
+
"""checks_embed with garbage bytes raises ValueError."""
|
|
326
|
+
monkeypatch.chdir(tmp_path)
|
|
327
|
+
|
|
328
|
+
with pytest.raises(ValueError, match="checks.toml:"):
|
|
329
|
+
strictcli.App(
|
|
330
|
+
name="testapp", version="1.0.0", help="test app",
|
|
331
|
+
checks_embed=b"\x80\x81 not valid toml {{{{",
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
def test_checks_embed_wrong_app_name(self, tmp_path, monkeypatch):
|
|
335
|
+
"""checks_embed with mismatched app name raises ValueError."""
|
|
336
|
+
monkeypatch.chdir(tmp_path)
|
|
337
|
+
wrong_toml = 'app = "wrong"\n'
|
|
338
|
+
|
|
339
|
+
with pytest.raises(
|
|
340
|
+
ValueError,
|
|
341
|
+
match=r'checks.toml: app "wrong" does not match app name "testapp"',
|
|
342
|
+
):
|
|
343
|
+
strictcli.App(
|
|
344
|
+
name="testapp", version="1.0.0", help="test app",
|
|
345
|
+
checks_embed=wrong_toml.encode(),
|
|
346
|
+
)
|
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
|
|
5
|
+
import pytest
|
|
5
6
|
import strictcli
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
@pytest.fixture(autouse=True)
|
|
10
|
+
def _pyproject_in_tmp(tmp_path):
|
|
11
|
+
"""Ensure every test that uses tmp_path has a pyproject.toml for project_id."""
|
|
12
|
+
(tmp_path / "pyproject.toml").write_text('[project]\nname = "testproject"\n')
|
|
13
|
+
|
|
14
|
+
|
|
8
15
|
CHECKS_TOML = """\
|
|
9
16
|
app = "testapp"
|
|
10
17
|
|
|
@@ -5,8 +5,17 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
7
|
|
|
8
|
+
import pytest
|
|
8
9
|
import strictcli
|
|
9
10
|
|
|
11
|
+
_PYPROJECT_TOML = '[project]\nname = "testproject"\n'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(autouse=True)
|
|
15
|
+
def _pyproject_in_tmp(tmp_path):
|
|
16
|
+
"""Ensure every test that uses tmp_path has a pyproject.toml for project_id."""
|
|
17
|
+
(tmp_path / "pyproject.toml").write_text(_PYPROJECT_TOML)
|
|
18
|
+
|
|
10
19
|
|
|
11
20
|
def _make_app(**kwargs):
|
|
12
21
|
"""Create a minimal app for testing."""
|
|
@@ -662,3 +671,60 @@ class TestSchemaNonDefaultValues:
|
|
|
662
671
|
app.test(["--dump-schema"])
|
|
663
672
|
data = json.loads((tmp_path / ".strictcli" / "schema.json").read_text())
|
|
664
673
|
assert data["config"] is True
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
class TestSchemaProjectId:
|
|
677
|
+
"""Schema contains project_id from pyproject.toml."""
|
|
678
|
+
|
|
679
|
+
def test_project_id_present(self, tmp_path, monkeypatch):
|
|
680
|
+
monkeypatch.chdir(tmp_path)
|
|
681
|
+
app = _make_app()
|
|
682
|
+
|
|
683
|
+
@app.command("noop", help="Does nothing")
|
|
684
|
+
def noop():
|
|
685
|
+
pass
|
|
686
|
+
|
|
687
|
+
app.test(["--dump-schema"])
|
|
688
|
+
data = json.loads((tmp_path / ".strictcli" / "schema.json").read_text())
|
|
689
|
+
assert data["project_id"] == "testproject"
|
|
690
|
+
|
|
691
|
+
def test_project_id_custom_name(self, tmp_path, monkeypatch):
|
|
692
|
+
(tmp_path / "pyproject.toml").write_text(
|
|
693
|
+
'[project]\nname = "my-custom-tool"\n'
|
|
694
|
+
)
|
|
695
|
+
monkeypatch.chdir(tmp_path)
|
|
696
|
+
app = _make_app()
|
|
697
|
+
|
|
698
|
+
@app.command("noop", help="Does nothing")
|
|
699
|
+
def noop():
|
|
700
|
+
pass
|
|
701
|
+
|
|
702
|
+
app.test(["--dump-schema"])
|
|
703
|
+
data = json.loads((tmp_path / ".strictcli" / "schema.json").read_text())
|
|
704
|
+
assert data["project_id"] == "my-custom-tool"
|
|
705
|
+
|
|
706
|
+
def test_project_id_error_no_pyproject(self, tmp_path, monkeypatch):
|
|
707
|
+
os.remove(tmp_path / "pyproject.toml")
|
|
708
|
+
monkeypatch.chdir(tmp_path)
|
|
709
|
+
app = _make_app()
|
|
710
|
+
|
|
711
|
+
@app.command("noop", help="Does nothing")
|
|
712
|
+
def noop():
|
|
713
|
+
pass
|
|
714
|
+
|
|
715
|
+
result = app.test(["--dump-schema"])
|
|
716
|
+
assert result.exit_code != 0
|
|
717
|
+
assert "project_id" in result.stderr
|
|
718
|
+
|
|
719
|
+
def test_project_id_error_no_project_name(self, tmp_path, monkeypatch):
|
|
720
|
+
(tmp_path / "pyproject.toml").write_text("[tool.something]\nkey = 1\n")
|
|
721
|
+
monkeypatch.chdir(tmp_path)
|
|
722
|
+
app = _make_app()
|
|
723
|
+
|
|
724
|
+
@app.command("noop", help="Does nothing")
|
|
725
|
+
def noop():
|
|
726
|
+
pass
|
|
727
|
+
|
|
728
|
+
result = app.test(["--dump-schema"])
|
|
729
|
+
assert result.exit_code != 0
|
|
730
|
+
assert "project_id" in result.stderr
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
permissions:
|
|
10
|
-
contents: read
|
|
11
|
-
id-token: write
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
pypi:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v6
|
|
18
|
-
- uses: astral-sh/setup-uv@v7
|
|
19
|
-
- run: uv build
|
|
20
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
21
|
-
|
|
22
|
-
npm:
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v6
|
|
26
|
-
- uses: actions/setup-node@v6
|
|
27
|
-
with:
|
|
28
|
-
node-version: 24
|
|
29
|
-
registry-url: https://registry.npmjs.org
|
|
30
|
-
- run: npm publish --provenance --access public
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
permissions:
|
|
10
|
-
contents: read
|
|
11
|
-
id-token: write
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
pypi:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v6
|
|
18
|
-
- uses: astral-sh/setup-uv@v7
|
|
19
|
-
- run: uv build
|
|
20
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
21
|
-
|
|
22
|
-
npm:
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v6
|
|
26
|
-
- uses: actions/setup-node@v6
|
|
27
|
-
with:
|
|
28
|
-
node-version: 24
|
|
29
|
-
registry-url: https://registry.npmjs.org
|
|
30
|
-
- run: npm publish --provenance --access public
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
c161283293520cc94f39d9cfec589f6f4cf5a352
|
|
File without changes
|
strictcli-0.12.0/.rlsbl/version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.45.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|