goga-tool-pybuggy 0.0.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.
- goga_tool_pybuggy-0.0.0/.github/workflows/publish.yml +17 -0
- goga_tool_pybuggy-0.0.0/.gitignore +231 -0
- goga_tool_pybuggy-0.0.0/.goga/config.yml +25 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/conventions.md +271 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/click.md +96 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/datamodel-code-generator.md +100 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/gitpython.md +90 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/goga.md +106 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/hamcrest.md +32 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/jinja2.md +108 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/jsonschema.md +61 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/pluginator.md +227 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/python-dotenv.md +50 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/requests.md +28 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/resq.md +100 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/ruamel-yaml.md +130 -0
- goga_tool_pybuggy-0.0.0/.goga/usages/cooks/swax-openapi.md +148 -0
- goga_tool_pybuggy-0.0.0/.goga/workflows/bugfix.yml +14 -0
- goga_tool_pybuggy-0.0.0/.goga/workflows/feature.yml +32 -0
- goga_tool_pybuggy-0.0.0/.goga/workflows/patch.yml +14 -0
- goga_tool_pybuggy-0.0.0/.goga/workflows/review.yml +2 -0
- goga_tool_pybuggy-0.0.0/LICENSE +28 -0
- goga_tool_pybuggy-0.0.0/PKG-INFO +46 -0
- goga_tool_pybuggy-0.0.0/README.md +1 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/.usages/assembly.md +92 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/.usages/retries.md +63 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/CODEMANIFEST +135 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/__init__.py +8 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/__main__.py +6 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/.usages/api.md +436 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/CODEMANIFEST +255 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/__init__.py +29 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/api.py +293 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/.usages/asserts.md +333 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/CODEMANIFEST +268 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/__init__.py +24 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/base.py +105 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/config.py +60 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/contexts.py +287 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/expected.py +368 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/asserts/field.py +605 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/auth.py +126 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/endpoint.py +174 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/api/response.py +87 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/cli.py +55 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/generate/.usages/generate.md +146 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/generate/CODEMANIFEST +125 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/generate/__init__.py +5 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/generate/generate.py +406 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/info/.usages/info.md +56 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/info/CODEMANIFEST +74 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/info/__init__.py +5 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/info/info.py +76 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/init/.usages/config-build.md +38 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/init/.usages/init.md +154 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/init/CODEMANIFEST +344 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/init/__init__.py +23 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/init/init.py +797 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/list/.usages/list.md +29 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/list/CODEMANIFEST +69 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/list/__init__.py +9 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/list/list.py +57 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/pull/.usages/pull.md +72 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/pull/CODEMANIFEST +84 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/pull/__init__.py +5 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/commands/pull/pull.py +270 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/.usages/configuration.md +36 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/CODEMANIFEST +89 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/__init__.py +13 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/config.py +22 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/git_entry.py +29 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/spec_entry.py +30 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/config/storage.py +45 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/env.py +50 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/.usages/matchcrest.md +108 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/CODEMANIFEST +117 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/__init__.py +82 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/.usages/matchers.md +103 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/CODEMANIFEST +409 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/__init__.py +85 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/base.py +128 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/error.py +62 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/response.py +234 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/matchers/value.py +775 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/utils/.usages/helpers.md +82 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/utils/CODEMANIFEST +119 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/utils/__init__.py +17 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/matchcrest/utils/utils.py +94 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/output/.usages/formatting.md +38 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/output/CODEMANIFEST +69 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/output/__init__.py +10 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/output/info.py +77 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/output/list.py +33 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/pipelines/api-feature.yml +59 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/.usages/configuration.md +129 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/.usages/enable.md +92 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/CODEMANIFEST +237 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/__init__.py +63 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/defaults.py +15 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/envvars.py +12 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/loaders/.usages/discovery.md +56 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/loaders/.usages/registration.md +74 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/loaders/CODEMANIFEST +110 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/loaders/__init__.py +20 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/loaders/loaders.py +250 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/plugin.py +357 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/plugin/render.py +42 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy/SKILL.md +112 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-cookbook/SKILL.md +149 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-apply/SKILL.md +110 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells/SKILL.md +113 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-cell-map/SKILL.md +78 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-context/SKILL.md +83 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-contracts/SKILL.md +114 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-intake/SKILL.md +84 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-libs/SKILL.md +125 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-plan-assembly/SKILL.md +107 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-plan-verification/SKILL.md +101 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-cells-review/SKILL.md +241 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-conftest/SKILL.md +94 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-design/SKILL.md +59 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-design-review/SKILL.md +62 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-plan/SKILL.md +79 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-plan-review/SKILL.md +73 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose/SKILL.md +73 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose-discovery/SKILL.md +103 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose-elaborate/SKILL.md +90 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose-intake/SKILL.md +85 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose-report/SKILL.md +86 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-propose-review/SKILL.md +233 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-review/SKILL.md +95 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases/SKILL.md +76 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases-discovery/SKILL.md +102 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases-intake/SKILL.md +96 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases-plan/SKILL.md +97 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases-review/SKILL.md +252 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-feature-testcases-write/SKILL.md +137 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/skills/pybuggy-api-usage/SKILL.md +36 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/.usages/spec.md +57 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/CODEMANIFEST +136 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/__init__.py +19 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/endpoint.py +42 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/endpoint_id.py +53 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/extract.py +269 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/spec/loader.py +28 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy/tools.py +42 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/PKG-INFO +46 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/SOURCES.txt +212 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/dependency_links.txt +1 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/entry_points.txt +2 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/requires.txt +30 -0
- goga_tool_pybuggy-0.0.0/goga_tool_pybuggy.egg-info/top_level.txt +1 -0
- goga_tool_pybuggy-0.0.0/pyproject.toml +134 -0
- goga_tool_pybuggy-0.0.0/setup.cfg +4 -0
- goga_tool_pybuggy-0.0.0/tests/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/api/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/api/conftest.py +92 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_api.py +285 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_api_request.py +265 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_assert_polling.py +232 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_auth.py +121 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_endpoint.py +494 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_field.py +208 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_integration_auth.py +107 -0
- goga_tool_pybuggy-0.0.0/tests/api/test_response_expected.py +345 -0
- goga_tool_pybuggy-0.0.0/tests/commands/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/commands/generate/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/commands/generate/test_generate.py +1187 -0
- goga_tool_pybuggy-0.0.0/tests/commands/info/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/commands/info/test_info.py +518 -0
- goga_tool_pybuggy-0.0.0/tests/commands/init/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/commands/init/test_init.py +1315 -0
- goga_tool_pybuggy-0.0.0/tests/commands/init/test_init_integration.py +180 -0
- goga_tool_pybuggy-0.0.0/tests/commands/list/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/commands/list/test_list.py +202 -0
- goga_tool_pybuggy-0.0.0/tests/commands/pull/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/commands/pull/test_pull.py +798 -0
- goga_tool_pybuggy-0.0.0/tests/config/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/config/test_Config.py +73 -0
- goga_tool_pybuggy-0.0.0/tests/config/test_GitEntry.py +75 -0
- goga_tool_pybuggy-0.0.0/tests/config/test_SpecEntry.py +82 -0
- goga_tool_pybuggy-0.0.0/tests/config/test_storage.py +148 -0
- goga_tool_pybuggy-0.0.0/tests/conftest.py +34 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/conftest.py +37 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/matchers/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/matchers/test_base.py +200 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/matchers/test_error.py +42 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/matchers/test_response.py +240 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/matchers/test_value.py +260 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/test_matchcrest.py +37 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/utils/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/matchcrest/utils/test_utils.py +216 -0
- goga_tool_pybuggy-0.0.0/tests/output/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/output/test_info.py +189 -0
- goga_tool_pybuggy-0.0.0/tests/output/test_list.py +123 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/loaders/__init__.py +0 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/loaders/test_loaders.py +380 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/test_install.py +81 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/test_integration.py +176 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/test_plugin.py +725 -0
- goga_tool_pybuggy-0.0.0/tests/plugin/test_render.py +123 -0
- goga_tool_pybuggy-0.0.0/tests/spec/__init__.py +1 -0
- goga_tool_pybuggy-0.0.0/tests/spec/test_Endpoint.py +196 -0
- goga_tool_pybuggy-0.0.0/tests/spec/test_endpoint_id.py +94 -0
- goga_tool_pybuggy-0.0.0/tests/spec/test_extract.py +1053 -0
- goga_tool_pybuggy-0.0.0/tests/spec/test_loader.py +83 -0
- goga_tool_pybuggy-0.0.0/tests/test_cli.py +17 -0
- goga_tool_pybuggy-0.0.0/tests/test_cli_env.py +177 -0
- goga_tool_pybuggy-0.0.0/tests/test_cli_integration.py +401 -0
- goga_tool_pybuggy-0.0.0/tests/test_env.py +141 -0
- goga_tool_pybuggy-0.0.0/tests/test_tools.py +64 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Publish Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
release:
|
|
12
|
+
uses: qarium/ci/.github/workflows/library-publish.yml@0.0.x
|
|
13
|
+
with:
|
|
14
|
+
src-package: 'goga-tool-pybuggy'
|
|
15
|
+
secrets:
|
|
16
|
+
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
17
|
+
ZAI_TOKEN: ${{ secrets.ZAI_TOKEN }}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
.libs/
|
|
4
|
+
|
|
5
|
+
# Byte-compiled / optimized / DLL files
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[codz]
|
|
8
|
+
*$py.class
|
|
9
|
+
|
|
10
|
+
# C extensions
|
|
11
|
+
*.so
|
|
12
|
+
|
|
13
|
+
# Distribution / packaging
|
|
14
|
+
.Python
|
|
15
|
+
build/
|
|
16
|
+
develop-eggs/
|
|
17
|
+
dist/
|
|
18
|
+
downloads/
|
|
19
|
+
eggs/
|
|
20
|
+
.eggs/
|
|
21
|
+
lib/
|
|
22
|
+
lib64/
|
|
23
|
+
parts/
|
|
24
|
+
sdist/
|
|
25
|
+
var/
|
|
26
|
+
wheels/
|
|
27
|
+
share/python-wheels/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
MANIFEST
|
|
32
|
+
|
|
33
|
+
# PyInstaller
|
|
34
|
+
# Usually these files are written by a python script from a template
|
|
35
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
36
|
+
*.manifest
|
|
37
|
+
*.spec
|
|
38
|
+
|
|
39
|
+
# Installer logs
|
|
40
|
+
pip-log.txt
|
|
41
|
+
pip-delete-this-directory.txt
|
|
42
|
+
|
|
43
|
+
# Unit test / coverage reports
|
|
44
|
+
htmlcov/
|
|
45
|
+
.tox/
|
|
46
|
+
.nox/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
.cache
|
|
50
|
+
nosetests.xml
|
|
51
|
+
coverage.xml
|
|
52
|
+
*.cover
|
|
53
|
+
*.py.cover
|
|
54
|
+
.hypothesis/
|
|
55
|
+
.pytest_cache/
|
|
56
|
+
cover/
|
|
57
|
+
|
|
58
|
+
# Translations
|
|
59
|
+
*.mo
|
|
60
|
+
*.pot
|
|
61
|
+
|
|
62
|
+
# Django stuff:
|
|
63
|
+
*.log
|
|
64
|
+
local_settings.py
|
|
65
|
+
db.sqlite3
|
|
66
|
+
db.sqlite3-journal
|
|
67
|
+
|
|
68
|
+
# Flask stuff:
|
|
69
|
+
instance/
|
|
70
|
+
.webassets-cache
|
|
71
|
+
|
|
72
|
+
# Scrapy stuff:
|
|
73
|
+
.scrapy
|
|
74
|
+
|
|
75
|
+
# Sphinx documentation
|
|
76
|
+
docs/_build/
|
|
77
|
+
|
|
78
|
+
# PyBuilder
|
|
79
|
+
.pybuilder/
|
|
80
|
+
target/
|
|
81
|
+
|
|
82
|
+
# Jupyter Notebook
|
|
83
|
+
.ipynb_checkpoints
|
|
84
|
+
|
|
85
|
+
# IPython
|
|
86
|
+
profile_default/
|
|
87
|
+
ipython_config.py
|
|
88
|
+
|
|
89
|
+
# pyenv
|
|
90
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
91
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
92
|
+
# .python-version
|
|
93
|
+
|
|
94
|
+
# pipenv
|
|
95
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
96
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
97
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
98
|
+
# install all needed dependencies.
|
|
99
|
+
# Pipfile.lock
|
|
100
|
+
|
|
101
|
+
# UV
|
|
102
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
103
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
104
|
+
# commonly ignored for libraries.
|
|
105
|
+
# uv.lock
|
|
106
|
+
|
|
107
|
+
# poetry
|
|
108
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
109
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
110
|
+
# commonly ignored for libraries.
|
|
111
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
112
|
+
# poetry.lock
|
|
113
|
+
# poetry.toml
|
|
114
|
+
|
|
115
|
+
# pdm
|
|
116
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
117
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
118
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
119
|
+
# pdm.lock
|
|
120
|
+
# pdm.toml
|
|
121
|
+
.pdm-python
|
|
122
|
+
.pdm-build/
|
|
123
|
+
|
|
124
|
+
# pixi
|
|
125
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
126
|
+
# pixi.lock
|
|
127
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
128
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
129
|
+
.pixi
|
|
130
|
+
|
|
131
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
132
|
+
__pypackages__/
|
|
133
|
+
|
|
134
|
+
# Celery stuff
|
|
135
|
+
celerybeat-schedule
|
|
136
|
+
celerybeat.pid
|
|
137
|
+
|
|
138
|
+
# Redis
|
|
139
|
+
*.rdb
|
|
140
|
+
*.aof
|
|
141
|
+
*.pid
|
|
142
|
+
|
|
143
|
+
# RabbitMQ
|
|
144
|
+
mnesia/
|
|
145
|
+
rabbitmq/
|
|
146
|
+
rabbitmq-data/
|
|
147
|
+
|
|
148
|
+
# ActiveMQ
|
|
149
|
+
activemq-data/
|
|
150
|
+
|
|
151
|
+
# SageMath parsed files
|
|
152
|
+
*.sage.py
|
|
153
|
+
|
|
154
|
+
# Environments
|
|
155
|
+
.env
|
|
156
|
+
.envrc
|
|
157
|
+
.venv
|
|
158
|
+
env/
|
|
159
|
+
venv/
|
|
160
|
+
ENV/
|
|
161
|
+
env.bak/
|
|
162
|
+
venv.bak/
|
|
163
|
+
|
|
164
|
+
# Spyder project settings
|
|
165
|
+
.spyderproject
|
|
166
|
+
.spyproject
|
|
167
|
+
|
|
168
|
+
# Rope project settings
|
|
169
|
+
.ropeproject
|
|
170
|
+
|
|
171
|
+
# mkdocs documentation
|
|
172
|
+
/site
|
|
173
|
+
|
|
174
|
+
# mypy
|
|
175
|
+
.mypy_cache/
|
|
176
|
+
.dmypy.json
|
|
177
|
+
dmypy.json
|
|
178
|
+
|
|
179
|
+
# Pyre type checker
|
|
180
|
+
.pyre/
|
|
181
|
+
|
|
182
|
+
# pytype static type analyzer
|
|
183
|
+
.pytype/
|
|
184
|
+
|
|
185
|
+
# Cython debug symbols
|
|
186
|
+
cython_debug/
|
|
187
|
+
|
|
188
|
+
# PyCharm
|
|
189
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
190
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
191
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
192
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
193
|
+
.idea/
|
|
194
|
+
|
|
195
|
+
# Abstra
|
|
196
|
+
# Abstra is an AI-powered process automation framework.
|
|
197
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
198
|
+
# Learn more at https://abstra.io/docs
|
|
199
|
+
.abstra/
|
|
200
|
+
|
|
201
|
+
# Visual Studio Code
|
|
202
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
203
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
204
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
205
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
206
|
+
# .vscode/
|
|
207
|
+
# Temporary file for partial code execution
|
|
208
|
+
tempCodeRunnerFile.py
|
|
209
|
+
|
|
210
|
+
# Ruff stuff:
|
|
211
|
+
.ruff_cache/
|
|
212
|
+
|
|
213
|
+
# PyPI configuration file
|
|
214
|
+
.pypirc
|
|
215
|
+
|
|
216
|
+
# Marimo
|
|
217
|
+
marimo/_static/
|
|
218
|
+
marimo/_lsp/
|
|
219
|
+
__marimo__/
|
|
220
|
+
|
|
221
|
+
# Streamlit
|
|
222
|
+
.streamlit/secrets.toml
|
|
223
|
+
|
|
224
|
+
# AI
|
|
225
|
+
.claude/
|
|
226
|
+
.ralphex/
|
|
227
|
+
#docs/tasks/
|
|
228
|
+
#docs/plans/
|
|
229
|
+
#docs/design/
|
|
230
|
+
#docs/arch/
|
|
231
|
+
docs/superpowers/
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
language: python
|
|
2
|
+
image: qarium/goga-python-3.13:1.1
|
|
3
|
+
|
|
4
|
+
.claude-env: &claude-env
|
|
5
|
+
ANTHROPIC_MODEL: opus
|
|
6
|
+
ANTHROPIC_BASE_URL: "https://api.z.ai/api/anthropic"
|
|
7
|
+
|
|
8
|
+
build:
|
|
9
|
+
task_executor:
|
|
10
|
+
agent: claude
|
|
11
|
+
env:
|
|
12
|
+
<<: *claude-env
|
|
13
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5.1"
|
|
14
|
+
|
|
15
|
+
pipeline:
|
|
16
|
+
agent: claude
|
|
17
|
+
env:
|
|
18
|
+
<<: *claude-env
|
|
19
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5.2[1m]"
|
|
20
|
+
|
|
21
|
+
codemanifest:
|
|
22
|
+
usages:
|
|
23
|
+
conventions: .goga/usages/conventions.md
|
|
24
|
+
annotations: |
|
|
25
|
+
Use `conventions` for code writing rules and testing.
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# General Conventions
|
|
2
|
+
|
|
3
|
+
Mandatory rules for all Python code in this project. Strict deterministic specification.
|
|
4
|
+
|
|
5
|
+
## Engineering Principles
|
|
6
|
+
|
|
7
|
+
Code in this repository MUST prioritize:
|
|
8
|
+
- readable, explicit code
|
|
9
|
+
- predictable, straightforward control flow
|
|
10
|
+
- stable abstractions
|
|
11
|
+
- operational stability and maintainability
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Development
|
|
16
|
+
|
|
17
|
+
## Constraints
|
|
18
|
+
|
|
19
|
+
- Compatible with Python 3.10 and above only
|
|
20
|
+
- Use `pyproject.toml` for configuration
|
|
21
|
+
- Execute all code within a virtualenv environment — create it if missing
|
|
22
|
+
|
|
23
|
+
## Imports
|
|
24
|
+
|
|
25
|
+
RULES:
|
|
26
|
+
1. Use relative imports for all intra-package references
|
|
27
|
+
2. Use absolute imports only for stdlib and third-party packages
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# Valid: intra-package
|
|
31
|
+
from .models import User
|
|
32
|
+
from ..utils import helper
|
|
33
|
+
|
|
34
|
+
# Valid: stdlib and third-party
|
|
35
|
+
import logging
|
|
36
|
+
from pydantic import BaseModel
|
|
37
|
+
|
|
38
|
+
# Forbidden: absolute import within the same package
|
|
39
|
+
from myapp.models import User
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
All subsequent import patterns MUST follow relative imports for intra-package references.
|
|
43
|
+
|
|
44
|
+
## Data Models
|
|
45
|
+
|
|
46
|
+
RULES:
|
|
47
|
+
1. Use pydantic for all data models and request/response schemas
|
|
48
|
+
2. All data model classes MUST use `kw_only=True` (Python 3.10+ syntax)
|
|
49
|
+
3. Set empty defaults (empty string, zero, etc.) for all fields — use `None` only for fields that represent the explicit absence of a value
|
|
50
|
+
|
|
51
|
+
## Logging
|
|
52
|
+
|
|
53
|
+
RULES:
|
|
54
|
+
1. Use `logging` as the default logging library
|
|
55
|
+
2. Use `structlog` when structured logging is required across the service
|
|
56
|
+
3. Use `loguru` only in single-file CLI utilities with a single entry point
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import logging
|
|
60
|
+
|
|
61
|
+
logger = logging.getLogger(__name__)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Operational logs **MUST**:
|
|
65
|
+
- include contextual metadata
|
|
66
|
+
- be machine-readable
|
|
67
|
+
- support filtering and aggregation
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
logger.info(
|
|
71
|
+
"user created",
|
|
72
|
+
extra={
|
|
73
|
+
"user_id": user.id,
|
|
74
|
+
"email": user.email,
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
All log output MUST follow structured format with contextual metadata.
|
|
80
|
+
|
|
81
|
+
Formatting:
|
|
82
|
+
- lowercase messages
|
|
83
|
+
- concise operational wording
|
|
84
|
+
- stable log event names
|
|
85
|
+
|
|
86
|
+
Log levels MUST reflect operational importance and required reaction.
|
|
87
|
+
|
|
88
|
+
### DEBUG
|
|
89
|
+
|
|
90
|
+
DEBUG is used for diagnostic information useful during development or incident investigation.
|
|
91
|
+
|
|
92
|
+
Use DEBUG for:
|
|
93
|
+
- intermediate state
|
|
94
|
+
- request/response details
|
|
95
|
+
- branch decisions
|
|
96
|
+
- retries
|
|
97
|
+
- external payload previews
|
|
98
|
+
- performance diagnostics
|
|
99
|
+
|
|
100
|
+
### INFO
|
|
101
|
+
|
|
102
|
+
INFO is used for important normal business operations.
|
|
103
|
+
|
|
104
|
+
INFO logs SHOULD describe:
|
|
105
|
+
- lifecycle events
|
|
106
|
+
- significant state transitions
|
|
107
|
+
- externally observable operations
|
|
108
|
+
|
|
109
|
+
### WARNING
|
|
110
|
+
|
|
111
|
+
WARNING indicates abnormal but recoverable situations.
|
|
112
|
+
The operation continues, but attention MAY be required.
|
|
113
|
+
|
|
114
|
+
Use WARNING when:
|
|
115
|
+
- fallback logic is activated
|
|
116
|
+
- retryable failures occur
|
|
117
|
+
- degraded behavior is detected
|
|
118
|
+
- unexpected input is received
|
|
119
|
+
|
|
120
|
+
### ERROR
|
|
121
|
+
|
|
122
|
+
ERROR is used when an operation cannot be completed.
|
|
123
|
+
|
|
124
|
+
Use ERROR when:
|
|
125
|
+
- a request fails
|
|
126
|
+
- data cannot be persisted
|
|
127
|
+
- external dependency prevents operation completion
|
|
128
|
+
- invariant violation affects functionality
|
|
129
|
+
|
|
130
|
+
### CRITICAL
|
|
131
|
+
|
|
132
|
+
CRITICAL is reserved for conditions requiring immediate operator intervention.
|
|
133
|
+
|
|
134
|
+
Use CRITICAL only when:
|
|
135
|
+
- the process cannot continue execution
|
|
136
|
+
- data corruption is detected or imminent
|
|
137
|
+
- core infrastructure dependencies are unreachable
|
|
138
|
+
- manual operator intervention is required within minutes
|
|
139
|
+
|
|
140
|
+
### Log Content Restrictions
|
|
141
|
+
|
|
142
|
+
Log messages MUST contain only non-sensitive operational data. Exclude secrets, credentials, tokens, and personal sensitive data from all log output.
|
|
143
|
+
|
|
144
|
+
## Code Formatting
|
|
145
|
+
|
|
146
|
+
Inside function and method bodies, logical blocks are separated by **one blank line**:
|
|
147
|
+
- Variable initialization is separated from conditional constructs and loops
|
|
148
|
+
- Loops and conditions are separated by a blank line
|
|
149
|
+
- Data preparation is separated from its processing
|
|
150
|
+
- Processing is separated from returning the result
|
|
151
|
+
|
|
152
|
+
## Docstrings
|
|
153
|
+
|
|
154
|
+
All public functions, methods, and classes **MUST** have docstrings. Format — **Google style**:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
def function_name(param1: str, param2: int = 0) -> bool:
|
|
158
|
+
"""Brief description of the function.
|
|
159
|
+
|
|
160
|
+
Detailed description when necessary.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
param1: Description of the first parameter.
|
|
164
|
+
param2: Description of the second parameter.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Description of the return value.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ValueError: Condition that triggers this exception.
|
|
171
|
+
"""
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Docstring rules:
|
|
175
|
+
- The first line is required, starts with a capital letter, ends with a period
|
|
176
|
+
- Include `Args` section when the function accepts parameters
|
|
177
|
+
- Include `Returns` section when the function returns a value
|
|
178
|
+
- Include `Raises` section when the function raises exceptions beyond built-in types
|
|
179
|
+
|
|
180
|
+
## Dependencies
|
|
181
|
+
|
|
182
|
+
All third-party libraries **MUST** be added to `pyproject.toml`. Specify a minimum version for every dependency.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
# Testing
|
|
187
|
+
|
|
188
|
+
## Constraints
|
|
189
|
+
|
|
190
|
+
- Test code must be compatible with Python 3.10 and above
|
|
191
|
+
|
|
192
|
+
## Tools
|
|
193
|
+
|
|
194
|
+
- pytest — running tests
|
|
195
|
+
- ruff — linting and formatting test code
|
|
196
|
+
- pytest-cov — coverage
|
|
197
|
+
|
|
198
|
+
## Running Tests
|
|
199
|
+
|
|
200
|
+
- Execute all tests within a virtualenv environment — create it if missing
|
|
201
|
+
|
|
202
|
+
## Test Structure
|
|
203
|
+
|
|
204
|
+
Tests mirror the source code structure **directly**, without an intermediate root package directory:
|
|
205
|
+
- `<src>/module/file.py` → `tests/module/test_file.py`
|
|
206
|
+
- The `tests/` directory contains subdirectories corresponding to nested packages of the root package
|
|
207
|
+
- Tests for root package modules (`__main__.py`, `__init__.py`) are placed directly in `tests/` (e.g., `tests/test_main.py`)
|
|
208
|
+
|
|
209
|
+
RULES:
|
|
210
|
+
1. Each test directory MUST contain an `__init__.py`
|
|
211
|
+
2. Place local fixtures in `tests/<package>/conftest.py`, shared fixtures in `tests/conftest.py`
|
|
212
|
+
3. Place integration tests covering multiple packages directly in `tests/` (e.g., `tests/test_integration.py`)
|
|
213
|
+
|
|
214
|
+
## Naming
|
|
215
|
+
|
|
216
|
+
- Files: `test_<module>.py`
|
|
217
|
+
- Functions: `test_<what>_<scenario>` (e.g., `test_complexity_with_empty_input`)
|
|
218
|
+
- Grouping: `class Test<Component>:`
|
|
219
|
+
|
|
220
|
+
## Test Types
|
|
221
|
+
|
|
222
|
+
- **Unit** — every public function/method/class, main scenario and typical data
|
|
223
|
+
- **Edge cases**:
|
|
224
|
+
- Empty inputs: `None`, `""`, `[]`, `{}`
|
|
225
|
+
- Boundary values: `0`, negative, very large
|
|
226
|
+
- Invalid types
|
|
227
|
+
- Expected exceptions via `pytest.raises`
|
|
228
|
+
- **Integration** — only for interaction between modules/packages
|
|
229
|
+
|
|
230
|
+
## REST API Testing
|
|
231
|
+
|
|
232
|
+
Test endpoints by calling the handler function directly via Python call.
|
|
233
|
+
|
|
234
|
+
## CLI Testing
|
|
235
|
+
|
|
236
|
+
Test CLI commands by calling the command handler function directly via Python call.
|
|
237
|
+
|
|
238
|
+
## Boundary Tests
|
|
239
|
+
|
|
240
|
+
For thresholds, ranges, state transitions — use `@pytest.mark.parametrize` with a table of values including each boundary.
|
|
241
|
+
|
|
242
|
+
## Mocks
|
|
243
|
+
|
|
244
|
+
- Pure logic — write tests without mocks
|
|
245
|
+
- File I/O — use the `tmp_path` fixture exclusively
|
|
246
|
+
- Subprocesses — `mock.patch` the subprocess call
|
|
247
|
+
- External dependencies — `mock.patch` at the import point
|
|
248
|
+
|
|
249
|
+
Mock only at external boundaries. Keep business logic tests mock-free.
|
|
250
|
+
|
|
251
|
+
## Miscellaneous
|
|
252
|
+
|
|
253
|
+
- Use self-documenting test names. Keep comments minimal.
|
|
254
|
+
- Skip integration tests with unavailable external dependencies via `pytest.mark.skipif`
|
|
255
|
+
|
|
256
|
+
## Dependencies
|
|
257
|
+
|
|
258
|
+
All test libraries **MUST** be added to `pyproject.toml` in the `[project.optional-dependencies]` section under the `test` key.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
# Validation Commands
|
|
263
|
+
|
|
264
|
+
All commands must run in a virtualenv environment. Python 3.10+ compatibility required.
|
|
265
|
+
|
|
266
|
+
| Purpose | Command |
|
|
267
|
+
|--------------------------|-------------------------------------------|
|
|
268
|
+
| Run all tests | `pytest tests/ -x` |
|
|
269
|
+
| Run a specific test | `pytest tests/test_<name>.py -v` |
|
|
270
|
+
| Lint | `ruff check <src>/` |
|
|
271
|
+
| Facade check | `python -c "from package import Entity"` |
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# click — CLI-фасад (библиотека)
|
|
2
|
+
|
|
3
|
+
## Предметная область
|
|
4
|
+
|
|
5
|
+
`click` — библиотека для построения CLI в Python. Используется проектом для групп, подгрупп,
|
|
6
|
+
команд, опций/аргументов и единообразного маппинга доменных ошибок в ненулевой exit.
|
|
7
|
+
|
|
8
|
+
```python
|
|
9
|
+
import click
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Эта практика описывает только API `click`. Как проект собирает из этого свой CLI — в клеточных
|
|
13
|
+
`.usages/` соответствующих ячеек (composition root, команды).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Группы и подгруппы
|
|
18
|
+
|
|
19
|
+
Группа (`@click.group`) — корень дерева команд. Подгруппа — отдельная группа, добавленная в
|
|
20
|
+
родительскую через `add_command`. Так строятся вложенные команды `parent child ...`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
@click.group()
|
|
24
|
+
def parent():
|
|
25
|
+
"""Root group."""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group("child", help="Child subgroup.")
|
|
29
|
+
def child_group():
|
|
30
|
+
"""Child subgroup."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
parent.add_command(child_group)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Имя группы — аргумент декоратора (`@click.group("child")`); без аргумента берётся имя функции.
|
|
37
|
+
- `help` группы показывается в `--help`.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Команды, опции, аргументы
|
|
42
|
+
|
|
43
|
+
Команда (`@click.command`) — лист дерева. Опции — `@click.option`, позиционные аргументы —
|
|
44
|
+
`@click.argument`. Имя декорированной функции — это имя команды, если не задано явно.
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
@click.command("pull")
|
|
48
|
+
@click.option("--spec", "spec_name", default=None, help="Filter by spec name.")
|
|
49
|
+
def pull_cmd(spec_name):
|
|
50
|
+
"""Pull specs."""
|
|
51
|
+
...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `@click.option("--flag", "dest", default=None, ...)` — опция; `dest` задаёт имя параметра в callback.
|
|
55
|
+
- Булев флаг: `is_flag=True, default=False`.
|
|
56
|
+
- Короткая форма: `@click.option("-s", "--spec", "spec_name", ...)`.
|
|
57
|
+
- `@click.argument("endpoint_id")` — позиционный аргумент.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Handler отделён от обёртки
|
|
62
|
+
|
|
63
|
+
Click-декоратор только связывает опции/аргументы и вызывает чистую handler-функцию. Это позволяет
|
|
64
|
+
тестировать логику **прямым вызовом** handler-а, без `CliRunner`:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
def run_pull(spec_name):
|
|
68
|
+
"""Pure handler — callable directly from tests."""
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@click.command("pull")
|
|
73
|
+
@click.option("--spec", "spec_name", default=None)
|
|
74
|
+
def pull_cmd(spec_name):
|
|
75
|
+
run_pull(spec_name)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Маппинг доменных ошибок — ClickException
|
|
81
|
+
|
|
82
|
+
Доменные ошибки (не найдено, невалидный ввод, отказ внешней зависимости) маппятся в
|
|
83
|
+
`click.ClickException`. Click печатает сообщение и завершает процесс с ненулевым exit —
|
|
84
|
+
единообразное поведение для всех команд:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
if spec_name not in config.specs:
|
|
88
|
+
raise click.ClickException(f"spec not found: {spec_name}")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Тестирование CLI
|
|
94
|
+
|
|
95
|
+
- Handler-функции тестируются **прямым вызовом** (см. `conventions`, раздел CLI Testing), без `CliRunner`.
|
|
96
|
+
- git/FS — через `mock.patch`/`tmp_path`; чистая логика — без моков.
|