bazis-cli 2.5.0__tar.gz → 2.6.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.
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/PKG-INFO +5 -4
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/README.md +3 -2
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/_version.py +3 -3
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/PKG-INFO +5 -4
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/SOURCES.txt +1 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/requires.txt +1 -1
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/scm_file_list.json +1 -0
- bazis_cli-2.6.0/bazis_cli.egg-info/scm_version.json +8 -0
- bazis_cli-2.6.0/docs/releases/2.6.0.md +15 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/evals/grade.py +57 -4
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/pyproject.toml +1 -1
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/tests/test_cli.py +12 -5
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/tests/test_evals.py +79 -5
- bazis_cli-2.5.0/bazis_cli.egg-info/scm_version.json +0 -8
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.dockerignore +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.github/workflows/build-publish.yml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.github/workflows/release.yml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.github/workflows/tests.yml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.github/workflows/update-licenses.yml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/.gitignore +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/CLAUDE.md +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/AGENTS.md +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/__init__.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/agent.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/bazis_manifest.toml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis/contrib/cli/main.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/dependency_links.txt +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/entry_points.txt +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/bazis_cli.egg-info/top_level.txt +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/docs/releases/2.4.0.md +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/docs/releases/2.4.1.md +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/docs/releases/2.5.0.md +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/evals/__init__.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/evals/run.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/evals/tasks.toml +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/setup.cfg +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/tests/__init__.py +0 -0
- {bazis_cli-2.5.0 → bazis_cli-2.6.0}/tests/conftest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bazis-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: The bazis command: creates, extends and audits Bazis products, backend and frontend, with Claude (Claude Agent SDK).
|
|
5
5
|
Author-email: Ilya Kharyn <ilya.tt07@gmail.com>
|
|
6
6
|
Maintainer-email: Ilya Kharyn <ilya.tt07@gmail.com>
|
|
@@ -19,7 +19,7 @@ Classifier: Framework :: FastAPI
|
|
|
19
19
|
Requires-Python: >=3.12
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
Requires-Dist: bazis>=2.16.0
|
|
22
|
-
Requires-Dist: bazis-mcp>=2.
|
|
22
|
+
Requires-Dist: bazis-mcp>=2.6.0
|
|
23
23
|
Requires-Dist: claude-agent-sdk>=0.2.163
|
|
24
24
|
Provides-Extra: test
|
|
25
25
|
Requires-Dist: pytest>=8; extra == "test"
|
|
@@ -82,8 +82,9 @@ bazis change # the changes typed one after another; an empty line ends
|
|
|
82
82
|
[bazis-front](https://github.com/ecofuture-tech/bazis-front): the specs of the product
|
|
83
83
|
(`spec/`: roles, entities, workflows, access, scenarios, screens, design), the backend
|
|
84
84
|
that satisfies them, the contract exported from it (`contract/`), a React + TypeScript
|
|
85
|
-
frontend (`frontend/`) with the screens
|
|
86
|
-
|
|
85
|
+
frontend (`frontend/`) with the screens generated from their specs (`bazis_front
|
|
86
|
+
screens`), the end-to-end tests of the scenarios run against the backend and the
|
|
87
|
+
screenshots of the screens looked at by the agent. It needs Node.js
|
|
87
88
|
22.12 or newer with npm, and PostgreSQL for the contract and the end-to-end tests;
|
|
88
89
|
`--no-frontend` builds only the backend.
|
|
89
90
|
- The product is in the language of its description and in English, the language of the
|
|
@@ -54,8 +54,9 @@ bazis change # the changes typed one after another; an empty line ends
|
|
|
54
54
|
[bazis-front](https://github.com/ecofuture-tech/bazis-front): the specs of the product
|
|
55
55
|
(`spec/`: roles, entities, workflows, access, scenarios, screens, design), the backend
|
|
56
56
|
that satisfies them, the contract exported from it (`contract/`), a React + TypeScript
|
|
57
|
-
frontend (`frontend/`) with the screens
|
|
58
|
-
|
|
57
|
+
frontend (`frontend/`) with the screens generated from their specs (`bazis_front
|
|
58
|
+
screens`), the end-to-end tests of the scenarios run against the backend and the
|
|
59
|
+
screenshots of the screens looked at by the agent. It needs Node.js
|
|
59
60
|
22.12 or newer with npm, and PostgreSQL for the contract and the end-to-end tests;
|
|
60
61
|
`--no-frontend` builds only the backend.
|
|
61
62
|
- The product is in the language of its description and in English, the language of the
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.6.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 6, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g04ed6b75d'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bazis-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: The bazis command: creates, extends and audits Bazis products, backend and frontend, with Claude (Claude Agent SDK).
|
|
5
5
|
Author-email: Ilya Kharyn <ilya.tt07@gmail.com>
|
|
6
6
|
Maintainer-email: Ilya Kharyn <ilya.tt07@gmail.com>
|
|
@@ -19,7 +19,7 @@ Classifier: Framework :: FastAPI
|
|
|
19
19
|
Requires-Python: >=3.12
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
Requires-Dist: bazis>=2.16.0
|
|
22
|
-
Requires-Dist: bazis-mcp>=2.
|
|
22
|
+
Requires-Dist: bazis-mcp>=2.6.0
|
|
23
23
|
Requires-Dist: claude-agent-sdk>=0.2.163
|
|
24
24
|
Provides-Extra: test
|
|
25
25
|
Requires-Dist: pytest>=8; extra == "test"
|
|
@@ -82,8 +82,9 @@ bazis change # the changes typed one after another; an empty line ends
|
|
|
82
82
|
[bazis-front](https://github.com/ecofuture-tech/bazis-front): the specs of the product
|
|
83
83
|
(`spec/`: roles, entities, workflows, access, scenarios, screens, design), the backend
|
|
84
84
|
that satisfies them, the contract exported from it (`contract/`), a React + TypeScript
|
|
85
|
-
frontend (`frontend/`) with the screens
|
|
86
|
-
|
|
85
|
+
frontend (`frontend/`) with the screens generated from their specs (`bazis_front
|
|
86
|
+
screens`), the end-to-end tests of the scenarios run against the backend and the
|
|
87
|
+
screenshots of the screens looked at by the agent. It needs Node.js
|
|
87
88
|
22.12 or newer with npm, and PostgreSQL for the contract and the end-to-end tests;
|
|
88
89
|
`--no-frontend` builds only the backend.
|
|
89
90
|
- The product is in the language of its description and in English, the language of the
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# bazis-cli 2.6.0
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
|
|
5
|
+
- bazis-cli requires bazis-mcp 2.6.0 (`bazis-mcp>=2.6.0`): the tasks and the rules of
|
|
6
|
+
bazis-front 0.3.0. A new product requires bazis-front 0.3.0; its screens are generated
|
|
7
|
+
from their specs (`bazis_front screens`), with an extension (`extend`) or a custom screen
|
|
8
|
+
(`custom`) only for what a spec cannot say, and its screenshots (`bazis_front shots`)
|
|
9
|
+
are taken and looked at, at most three rounds. A change of a product generates its
|
|
10
|
+
screens again and ends with the whole round of the final checks.
|
|
11
|
+
- The evals grade the screens of a product: `bazis_front screens --check` and `bazis_front
|
|
12
|
+
shots --check` (a comparison with the specs, the screenshots not taken by the grader)
|
|
13
|
+
with `design` and `e2e`, and no TSX of the product in `frontend/src/` but the code of its
|
|
14
|
+
custom and extended screens (the copies, the generated screens and the template are not
|
|
15
|
+
its own); the detail counts the lines of TSX written by hand.
|
|
@@ -18,14 +18,16 @@ Python of the project (`.venv`) against PostgreSQL and Redis of `.env`. It does
|
|
|
18
18
|
on the names the agent chose: it checks that the project loads and passes its checks, has
|
|
19
19
|
the expected Bazis packages, complete migrations that apply, models and routes of its own,
|
|
20
20
|
and tests that pass. A product with a frontend (`frontend = true`) also needs specs valid
|
|
21
|
-
against a fresh contract, generated files that are not stale,
|
|
22
|
-
|
|
21
|
+
against a fresh contract, generated files that are not stale, screens generated from their
|
|
22
|
+
specs (no TSX of its own but that of its custom and extended screens), a frontend that
|
|
23
|
+
builds and passes its lint and component tests, and end-to-end tests of its scenarios that pass
|
|
23
24
|
against the backend with the test data of `manage.py e2e_data` (Node.js is needed). A task
|
|
24
25
|
with a `language` needs the product in that language and in English, with its catalog.
|
|
25
26
|
The grader runs on POSIX only (macOS, Linux): it stops the servers and the commands it
|
|
26
27
|
starts by their process group.
|
|
27
28
|
"""
|
|
28
29
|
|
|
30
|
+
import json
|
|
29
31
|
import os
|
|
30
32
|
import re
|
|
31
33
|
import secrets
|
|
@@ -49,6 +51,17 @@ BAZIS_CHECK_PREFIXES = (
|
|
|
49
51
|
'async_request.', 'bg.', 'front.',
|
|
50
52
|
)
|
|
51
53
|
TIMEOUT = 900
|
|
54
|
+
#: the TSX of `frontend/src/` that a product does not write: the generated screens and the
|
|
55
|
+
#: template (its entry, its app and its login), besides the assets that bazis-front copied
|
|
56
|
+
#: (the files of `assets` in its lock, among them the shadcn components of `components/ui/`)
|
|
57
|
+
NOT_WRITTEN = ('bazis/', 'screens/generated/', 'main.tsx', 'app/', 'screens/login/')
|
|
58
|
+
#: prints `custom` and `extend` of the specs of the screens by their ids, as JSON (run with the
|
|
59
|
+
#: Python of the project, which has PyYAML with bazis-front)
|
|
60
|
+
SCREEN_SPECS = """\
|
|
61
|
+
import json, pathlib, yaml
|
|
62
|
+
specs = [yaml.safe_load(path.read_text(encoding='utf-8')) for path in pathlib.Path('spec/screens').glob('*.yaml')]
|
|
63
|
+
print(json.dumps({it['id']: {key: it[key] for key in ('custom', 'extend') if key in it} for it in specs}))
|
|
64
|
+
"""
|
|
52
65
|
|
|
53
66
|
|
|
54
67
|
@dataclass
|
|
@@ -278,12 +291,14 @@ def frontend_checks(project: Path, env: dict, min_scenarios: int) -> list[Check]
|
|
|
278
291
|
stale = [
|
|
279
292
|
done for done in (
|
|
280
293
|
run(project, ['manage.py', 'bazis_front', command, '--check'], env)
|
|
281
|
-
for command in ('design', 'e2e')
|
|
294
|
+
for command in ('design', 'screens', 'e2e', 'shots')
|
|
282
295
|
) if done.returncode
|
|
283
296
|
]
|
|
284
297
|
checks.append(Check(
|
|
285
|
-
'theme
|
|
298
|
+
'theme, screens, end-to-end tests and screenshots generated', not stale,
|
|
299
|
+
'\n'.join(tail(d, 4) for d in stale),
|
|
286
300
|
))
|
|
301
|
+
checks.append(written_screens(project, env))
|
|
287
302
|
|
|
288
303
|
build = npm(frontend, ['run', 'build'], env)
|
|
289
304
|
checks.append(Check('frontend builds', build.returncode == 0, tail(build, 8)))
|
|
@@ -298,6 +313,44 @@ def frontend_checks(project: Path, env: dict, min_scenarios: int) -> list[Check]
|
|
|
298
313
|
return checks
|
|
299
314
|
|
|
300
315
|
|
|
316
|
+
def written_screens(project: Path, env: dict) -> Check:
|
|
317
|
+
"""
|
|
318
|
+
The screens are generated from their specs: the TSX that the product writes in
|
|
319
|
+
`frontend/src/` (not NOT_WRITTEN) is only the code of a custom screen (`custom`: its
|
|
320
|
+
directory `screens/<id>/`, or the module it names) or of an extended one (`extend`: its
|
|
321
|
+
directory). The detail counts the lines of that TSX, a measure of the hand-written code.
|
|
322
|
+
"""
|
|
323
|
+
title = 'no TSX of its own but that of the custom and extended screens'
|
|
324
|
+
specs = run(project, ['-c', SCREEN_SPECS], env)
|
|
325
|
+
screens = mcp_project.parse_json(specs.stdout)
|
|
326
|
+
if screens is None:
|
|
327
|
+
return Check(title, False, 'the specs of the screens: ' + tail(specs, 4))
|
|
328
|
+
allowed = []
|
|
329
|
+
for id_, spec in screens.items():
|
|
330
|
+
custom = spec.get('custom')
|
|
331
|
+
if custom is True or spec.get('extend'):
|
|
332
|
+
allowed.append(f'screens/{id_}/')
|
|
333
|
+
elif custom:
|
|
334
|
+
module = custom['module'].removeprefix('@/')
|
|
335
|
+
allowed += [f'{module}.tsx', f'{module}/']
|
|
336
|
+
source = project / 'frontend' / 'src'
|
|
337
|
+
lock = json.loads((project / 'frontend' / 'bazis-front.lock.json').read_text(encoding='utf-8'))
|
|
338
|
+
copied = {
|
|
339
|
+
file.removeprefix('src/') for asset in lock['assets'].values() for file in asset.get('files', ())
|
|
340
|
+
}
|
|
341
|
+
written = {
|
|
342
|
+
name: path for path in sorted(source.rglob('*.tsx'))
|
|
343
|
+
if not (name := path.relative_to(source).as_posix()).startswith(NOT_WRITTEN)
|
|
344
|
+
and name not in copied
|
|
345
|
+
}
|
|
346
|
+
lines = sum(len(path.read_text(encoding='utf-8').splitlines()) for path in written.values())
|
|
347
|
+
other = [name for name in written if not name.startswith(tuple(allowed))]
|
|
348
|
+
detail = f'lines of TSX written by hand: {lines}'
|
|
349
|
+
if other:
|
|
350
|
+
detail += '; not of a custom or extended screen: ' + ', '.join(other)
|
|
351
|
+
return Check(title, not other, detail)
|
|
352
|
+
|
|
353
|
+
|
|
301
354
|
def project_package(project: Path) -> str:
|
|
302
355
|
"""
|
|
303
356
|
The project package, from DJANGO_SETTINGS_MODULE of manage.py.
|
|
@@ -37,7 +37,7 @@ dependencies = [
|
|
|
37
37
|
# the settings of a project without .venv (--no-venv), the languages of Django and the
|
|
38
38
|
# modules a project package must not hide are those of the Python of the CLI
|
|
39
39
|
"bazis>=2.16.0",
|
|
40
|
-
"bazis-mcp>=2.
|
|
40
|
+
"bazis-mcp>=2.6.0",
|
|
41
41
|
"claude-agent-sdk>=0.2.163",
|
|
42
42
|
]
|
|
43
43
|
|
|
@@ -337,8 +337,11 @@ def test_add_to_a_product_with_a_frontend(tmp_path, fake_agent, capsys):
|
|
|
337
337
|
assert 'package_guide("bazis-statusy")' in backend
|
|
338
338
|
# a project made before the ports gets them
|
|
339
339
|
assert prompts.ports_text(scaffold.project_ports(tmp_path)) in frontend
|
|
340
|
-
|
|
341
|
-
|
|
340
|
+
# the screens generated again, then the whole round of the final checks (bazis-mcp 2.6)
|
|
341
|
+
frontend = ' '.join(frontend.split())
|
|
342
|
+
order = ['spec/', 'bazis_front contract', 'front_check', 'bazis_front screens',
|
|
343
|
+
'bazis_front e2e', 'e2e_data', 'the whole round of the final checks of the rules',
|
|
344
|
+
'npm run build', 'bazis_front screens --check']
|
|
342
345
|
positions = [frontend.index(text) for text in order]
|
|
343
346
|
assert positions == sorted(positions)
|
|
344
347
|
assert FRONTEND_RULES in options.system_prompt['append']
|
|
@@ -359,7 +362,7 @@ def test_add_the_frontend(tmp_path, fake_agent):
|
|
|
359
362
|
assert '"Building the frontend of a product"' in prompt
|
|
360
363
|
assert 'the final checks of the rules' in prompt
|
|
361
364
|
assert 'the specs describe the backend and what the project needs it for' in prompt
|
|
362
|
-
assert 'requirement `
|
|
365
|
+
assert f'requirement `{scaffold.FRONTEND_REQUIREMENT}`' in prompt
|
|
363
366
|
assert FRONTEND_RULES in options.system_prompt['append']
|
|
364
367
|
|
|
365
368
|
|
|
@@ -372,7 +375,7 @@ def test_add_the_frontend_from_a_build(tmp_path, fake_agent, monkeypatch):
|
|
|
372
375
|
|
|
373
376
|
prompt, _ = fake_agent[0]
|
|
374
377
|
assert 'requirement `/wheels/bazis_front-0.1.0.whl`' in prompt
|
|
375
|
-
assert
|
|
378
|
+
assert scaffold.FRONTEND_REQUIREMENT not in prompt
|
|
376
379
|
|
|
377
380
|
|
|
378
381
|
def test_add_without_node(tmp_path, fake_agent, monkeypatch, capsys):
|
|
@@ -505,7 +508,11 @@ def test_change(tmp_path, fake_agent, sessions, capsys):
|
|
|
505
508
|
assert main.main(['change', 'Add the authors', *project, '--budget', '2']) == 0
|
|
506
509
|
prompt, options = fake_agent[-1]
|
|
507
510
|
assert options.resume == 's' and options.max_budget_usd == 2
|
|
508
|
-
|
|
511
|
+
# the request, the final checks once, and the headings of the summary (bazis-mcp 2.6)
|
|
512
|
+
assert prompt == (
|
|
513
|
+
'Add the authors\n\nAfter the change, run the final checks of the rules once.\n\n'
|
|
514
|
+
f'{prompts.SUMMARY}\n'
|
|
515
|
+
)
|
|
509
516
|
|
|
510
517
|
assert main.main(['change', 'Add the authors', *project, '--new-session']) == 0
|
|
511
518
|
assert fake_agent[-1][1].resume is None
|
|
@@ -17,6 +17,8 @@ import os
|
|
|
17
17
|
import subprocess
|
|
18
18
|
import time
|
|
19
19
|
|
|
20
|
+
import pytest
|
|
21
|
+
|
|
20
22
|
from bazis.contrib.mcp import catalog, scaffold
|
|
21
23
|
|
|
22
24
|
from evals import grade, run
|
|
@@ -111,8 +113,6 @@ def test_summary(tmp_path):
|
|
|
111
113
|
|
|
112
114
|
|
|
113
115
|
def test_running_needs_a_budget():
|
|
114
|
-
import pytest
|
|
115
|
-
|
|
116
116
|
with pytest.raises(SystemExit, match='budget'):
|
|
117
117
|
run.main_cli(['--task', 'tracker'])
|
|
118
118
|
|
|
@@ -125,7 +125,7 @@ def product(tmp_path, scenarios: int):
|
|
|
125
125
|
scaffold.write_files(tmp_path, 'desk', frontend=True)
|
|
126
126
|
generated = tmp_path / 'frontend' / 'e2e' / 'generated'
|
|
127
127
|
generated.mkdir(parents=True)
|
|
128
|
-
(tmp_path / 'frontend' / 'bazis-front.lock.json').write_text('{}')
|
|
128
|
+
(tmp_path / 'frontend' / 'bazis-front.lock.json').write_text('{"assets": {}}')
|
|
129
129
|
for index in range(scenarios):
|
|
130
130
|
(generated / f'scenario-{index}.spec.ts').write_text('')
|
|
131
131
|
(generated / 'product.ts').write_text('')
|
|
@@ -139,6 +139,8 @@ def test_frontend_checks(tmp_path, monkeypatch):
|
|
|
139
139
|
|
|
140
140
|
def fake_run(project, args, env):
|
|
141
141
|
commands.append(args)
|
|
142
|
+
if args[0] == '-c':
|
|
143
|
+
return done(0, '{}')
|
|
142
144
|
if args[2] == 'check':
|
|
143
145
|
return done(1, json.dumps({'contract': True, 'errors': 1, 'warnings': 1, 'issues': issues}))
|
|
144
146
|
return done(1 if args[2] == 'e2e' else 0)
|
|
@@ -153,10 +155,82 @@ def test_frontend_checks(tmp_path, monkeypatch):
|
|
|
153
155
|
assert checks['specs valid against the contract'].detail == 'P019 spec/product.yaml#/roles/0'
|
|
154
156
|
assert not checks['at least 3 scenarios'].passed
|
|
155
157
|
assert checks['at least 3 scenarios'].detail == 'scenario-0.spec, scenario-1.spec'
|
|
156
|
-
assert not checks['theme
|
|
158
|
+
assert not checks['theme, screens, end-to-end tests and screenshots generated'].passed
|
|
159
|
+
assert checks['no TSX of its own but that of the custom and extended screens'].passed
|
|
157
160
|
assert checks['frontend builds'].passed
|
|
158
161
|
assert not checks['frontend lint and component tests pass'].passed
|
|
159
|
-
|
|
162
|
+
for command in ('design', 'screens', 'e2e', 'shots'):
|
|
163
|
+
assert ['manage.py', 'bazis_front', command, '--check'] in commands
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_written_screens(tmp_path, monkeypatch):
|
|
167
|
+
"""
|
|
168
|
+
The TSX that a product writes is only that of its custom and extended screens: not of a
|
|
169
|
+
screen generated from its spec, nor elsewhere in `src/`; the copies, the generated
|
|
170
|
+
screens and the template are not its own. The lines written are counted.
|
|
171
|
+
"""
|
|
172
|
+
screens = {
|
|
173
|
+
'loan-list': {'custom': True},
|
|
174
|
+
'book-card': {'extend': True},
|
|
175
|
+
'reader-list': {'custom': {'module': '@/screens/readers', 'export': 'ReaderListScreen'}},
|
|
176
|
+
'book-list': {},
|
|
177
|
+
}
|
|
178
|
+
monkeypatch.setattr(grade, 'run', lambda project, args, env: done(0, json.dumps(screens)))
|
|
179
|
+
source = tmp_path / 'frontend' / 'src'
|
|
180
|
+
files = {
|
|
181
|
+
# the custom and extended screens, their own files too
|
|
182
|
+
'screens/loan-list/index.tsx': 3, 'screens/loan-list/parts.tsx': 2,
|
|
183
|
+
'screens/book-card/extend.tsx': 4, 'screens/readers.tsx': 1,
|
|
184
|
+
# not the product's
|
|
185
|
+
'screens/generated/book-list.tsx': 50, 'bazis/ui/list/index.tsx': 50,
|
|
186
|
+
'app/router.tsx': 50, 'main.tsx': 50, 'screens/login/index.tsx': 50,
|
|
187
|
+
'screens/book-list/index.tsx': 5, 'components/badge.tsx': 6,
|
|
188
|
+
'screens/loan-list-extra/index.tsx': 7, 'i18n/en.ts': 50,
|
|
189
|
+
# the screen of a custom module elsewhere has no directory of its own
|
|
190
|
+
'screens/reader-list/index.tsx': 8,
|
|
191
|
+
}
|
|
192
|
+
for name, lines in files.items():
|
|
193
|
+
(source / name).parent.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
(source / name).write_text('x\n' * lines)
|
|
195
|
+
# the shadcn components that bazis-front copied are in its lock: not the product's
|
|
196
|
+
(source / 'components' / 'ui').mkdir(parents=True)
|
|
197
|
+
(source / 'components' / 'ui' / 'button.tsx').write_text('x\n' * 100)
|
|
198
|
+
(source.parent / 'bazis-front.lock.json').write_text(json.dumps({
|
|
199
|
+
# an entry of an old dev-lock has no `files`
|
|
200
|
+
'assets': {'button': {'files': {'src/components/ui/button.tsx': 'sha256:0'}}, 'old': {}},
|
|
201
|
+
}))
|
|
202
|
+
|
|
203
|
+
check = grade.written_screens(tmp_path, {})
|
|
204
|
+
|
|
205
|
+
assert not check.passed and check.name.startswith('no TSX of its own')
|
|
206
|
+
assert check.detail == (
|
|
207
|
+
'lines of TSX written by hand: 36; not of a custom or extended screen: '
|
|
208
|
+
'components/badge.tsx, screens/book-list/index.tsx, screens/loan-list-extra/index.tsx, '
|
|
209
|
+
'screens/reader-list/index.tsx'
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
for name in ('screens/book-list/index.tsx', 'components/badge.tsx', 'screens/loan-list-extra/index.tsx',
|
|
213
|
+
'screens/reader-list/index.tsx'):
|
|
214
|
+
(source / name).unlink()
|
|
215
|
+
check = grade.written_screens(tmp_path, {})
|
|
216
|
+
assert check.passed and check.detail == 'lines of TSX written by hand: 10'
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_written_screens_reads_the_specs(tmp_path):
|
|
220
|
+
"""
|
|
221
|
+
The specs of the screens are read with the Python of the project (PyYAML of bazis-front).
|
|
222
|
+
"""
|
|
223
|
+
pytest.importorskip('yaml')
|
|
224
|
+
(tmp_path / 'spec' / 'screens').mkdir(parents=True)
|
|
225
|
+
(tmp_path / 'spec' / 'screens' / 'loan-list.yaml').write_text('id: loan-list\ncustom: true\n')
|
|
226
|
+
(tmp_path / 'spec' / 'screens' / 'book-list.yaml').write_text('id: book-list\nprimitive: list\n')
|
|
227
|
+
(tmp_path / 'frontend' / 'src' / 'screens' / 'loan-list').mkdir(parents=True)
|
|
228
|
+
(tmp_path / 'frontend' / 'src' / 'screens' / 'loan-list' / 'index.tsx').write_text('x\n')
|
|
229
|
+
(tmp_path / 'frontend' / 'bazis-front.lock.json').write_text('{"assets": {}}')
|
|
230
|
+
|
|
231
|
+
check = grade.written_screens(tmp_path, {**os.environ})
|
|
232
|
+
|
|
233
|
+
assert check.passed and check.detail == 'lines of TSX written by hand: 1'
|
|
160
234
|
|
|
161
235
|
|
|
162
236
|
def test_frontend_checks_without_a_frontend(tmp_path):
|
|
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
|