solokit 0.1.1__py3-none-any.whl
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.
- solokit/__init__.py +10 -0
- solokit/__version__.py +3 -0
- solokit/cli.py +374 -0
- solokit/core/__init__.py +1 -0
- solokit/core/cache.py +102 -0
- solokit/core/command_runner.py +278 -0
- solokit/core/config.py +453 -0
- solokit/core/config_validator.py +204 -0
- solokit/core/constants.py +291 -0
- solokit/core/error_formatter.py +279 -0
- solokit/core/error_handlers.py +346 -0
- solokit/core/exceptions.py +1567 -0
- solokit/core/file_ops.py +309 -0
- solokit/core/logging_config.py +166 -0
- solokit/core/output.py +99 -0
- solokit/core/performance.py +57 -0
- solokit/core/protocols.py +141 -0
- solokit/core/types.py +312 -0
- solokit/deployment/__init__.py +1 -0
- solokit/deployment/executor.py +411 -0
- solokit/git/__init__.py +1 -0
- solokit/git/integration.py +619 -0
- solokit/init/__init__.py +41 -0
- solokit/init/claude_commands_installer.py +87 -0
- solokit/init/dependency_installer.py +313 -0
- solokit/init/docs_structure.py +90 -0
- solokit/init/env_generator.py +160 -0
- solokit/init/environment_validator.py +334 -0
- solokit/init/git_hooks_installer.py +71 -0
- solokit/init/git_setup.py +188 -0
- solokit/init/gitignore_updater.py +195 -0
- solokit/init/initial_commit.py +145 -0
- solokit/init/initial_scans.py +109 -0
- solokit/init/orchestrator.py +246 -0
- solokit/init/readme_generator.py +207 -0
- solokit/init/session_structure.py +239 -0
- solokit/init/template_installer.py +424 -0
- solokit/learning/__init__.py +1 -0
- solokit/learning/archiver.py +115 -0
- solokit/learning/categorizer.py +126 -0
- solokit/learning/curator.py +428 -0
- solokit/learning/extractor.py +352 -0
- solokit/learning/reporter.py +351 -0
- solokit/learning/repository.py +254 -0
- solokit/learning/similarity.py +342 -0
- solokit/learning/validator.py +144 -0
- solokit/project/__init__.py +1 -0
- solokit/project/init.py +1162 -0
- solokit/project/stack.py +436 -0
- solokit/project/sync_plugin.py +438 -0
- solokit/project/tree.py +375 -0
- solokit/quality/__init__.py +1 -0
- solokit/quality/api_validator.py +424 -0
- solokit/quality/checkers/__init__.py +25 -0
- solokit/quality/checkers/base.py +114 -0
- solokit/quality/checkers/context7.py +221 -0
- solokit/quality/checkers/custom.py +162 -0
- solokit/quality/checkers/deployment.py +323 -0
- solokit/quality/checkers/documentation.py +179 -0
- solokit/quality/checkers/formatting.py +161 -0
- solokit/quality/checkers/integration.py +394 -0
- solokit/quality/checkers/linting.py +159 -0
- solokit/quality/checkers/security.py +261 -0
- solokit/quality/checkers/spec_completeness.py +127 -0
- solokit/quality/checkers/tests.py +184 -0
- solokit/quality/env_validator.py +306 -0
- solokit/quality/gates.py +655 -0
- solokit/quality/reporters/__init__.py +10 -0
- solokit/quality/reporters/base.py +25 -0
- solokit/quality/reporters/console.py +98 -0
- solokit/quality/reporters/json_reporter.py +34 -0
- solokit/quality/results.py +98 -0
- solokit/session/__init__.py +1 -0
- solokit/session/briefing/__init__.py +245 -0
- solokit/session/briefing/documentation_loader.py +53 -0
- solokit/session/briefing/formatter.py +476 -0
- solokit/session/briefing/git_context.py +282 -0
- solokit/session/briefing/learning_loader.py +212 -0
- solokit/session/briefing/milestone_builder.py +78 -0
- solokit/session/briefing/orchestrator.py +137 -0
- solokit/session/briefing/stack_detector.py +51 -0
- solokit/session/briefing/tree_generator.py +52 -0
- solokit/session/briefing/work_item_loader.py +209 -0
- solokit/session/briefing.py +353 -0
- solokit/session/complete.py +1188 -0
- solokit/session/status.py +246 -0
- solokit/session/validate.py +452 -0
- solokit/templates/.claude/commands/end.md +109 -0
- solokit/templates/.claude/commands/init.md +159 -0
- solokit/templates/.claude/commands/learn-curate.md +88 -0
- solokit/templates/.claude/commands/learn-search.md +62 -0
- solokit/templates/.claude/commands/learn-show.md +69 -0
- solokit/templates/.claude/commands/learn.md +136 -0
- solokit/templates/.claude/commands/start.md +114 -0
- solokit/templates/.claude/commands/status.md +22 -0
- solokit/templates/.claude/commands/validate.md +27 -0
- solokit/templates/.claude/commands/work-delete.md +119 -0
- solokit/templates/.claude/commands/work-graph.md +139 -0
- solokit/templates/.claude/commands/work-list.md +26 -0
- solokit/templates/.claude/commands/work-new.md +114 -0
- solokit/templates/.claude/commands/work-next.md +25 -0
- solokit/templates/.claude/commands/work-show.md +24 -0
- solokit/templates/.claude/commands/work-update.md +141 -0
- solokit/templates/CHANGELOG.md +17 -0
- solokit/templates/WORK_ITEM_TYPES.md +141 -0
- solokit/templates/__init__.py +1 -0
- solokit/templates/bug_spec.md +217 -0
- solokit/templates/config.schema.json +150 -0
- solokit/templates/dashboard_refine/base/.gitignore +36 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
- solokit/templates/dashboard_refine/base/app/globals.css +60 -0
- solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
- solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
- solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
- solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
- solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
- solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
- solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
- solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
- solokit/templates/dashboard_refine/base/components.json +16 -0
- solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
- solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
- solokit/templates/dashboard_refine/base/next.config.ts +10 -0
- solokit/templates/dashboard_refine/base/package.json.template +40 -0
- solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
- solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
- solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
- solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
- solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
- solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
- solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
- solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
- solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
- solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
- solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
- solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/deployment_spec.md +500 -0
- solokit/templates/feature_spec.md +248 -0
- solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
- solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
- solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
- solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
- solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
- solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
- solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
- solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
- solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
- solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
- solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
- solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
- solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
- solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
- solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
- solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
- solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/git-hooks/prepare-commit-msg +24 -0
- solokit/templates/integration_test_spec.md +363 -0
- solokit/templates/learnings.json +15 -0
- solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
- solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
- solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
- solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
- solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
- solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
- solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
- solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
- solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
- solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
- solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
- solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
- solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
- solokit/templates/refactor_spec.md +287 -0
- solokit/templates/saas_t3/base/.gitignore +36 -0
- solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
- solokit/templates/saas_t3/base/app/globals.css +27 -0
- solokit/templates/saas_t3/base/app/layout.tsx +23 -0
- solokit/templates/saas_t3/base/app/page.tsx +31 -0
- solokit/templates/saas_t3/base/lib/api.tsx +77 -0
- solokit/templates/saas_t3/base/lib/utils.ts +13 -0
- solokit/templates/saas_t3/base/next.config.ts +7 -0
- solokit/templates/saas_t3/base/package.json.template +38 -0
- solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
- solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
- solokit/templates/saas_t3/base/server/api/root.ts +19 -0
- solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
- solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
- solokit/templates/saas_t3/base/server/db.ts +17 -0
- solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
- solokit/templates/saas_t3/base/tsconfig.json +27 -0
- solokit/templates/saas_t3/docker/Dockerfile +60 -0
- solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
- solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
- solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
- solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
- solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
- solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
- solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
- solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
- solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
- solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
- solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
- solokit/templates/security_spec.md +287 -0
- solokit/templates/stack-versions.yaml +617 -0
- solokit/templates/status_update.json +6 -0
- solokit/templates/template-registry.json +257 -0
- solokit/templates/work_items.json +11 -0
- solokit/testing/__init__.py +1 -0
- solokit/testing/integration_runner.py +550 -0
- solokit/testing/performance.py +637 -0
- solokit/visualization/__init__.py +1 -0
- solokit/visualization/dependency_graph.py +788 -0
- solokit/work_items/__init__.py +1 -0
- solokit/work_items/creator.py +217 -0
- solokit/work_items/delete.py +264 -0
- solokit/work_items/get_dependencies.py +185 -0
- solokit/work_items/get_dependents.py +113 -0
- solokit/work_items/get_metadata.py +121 -0
- solokit/work_items/get_next_recommendations.py +133 -0
- solokit/work_items/manager.py +235 -0
- solokit/work_items/milestones.py +137 -0
- solokit/work_items/query.py +376 -0
- solokit/work_items/repository.py +267 -0
- solokit/work_items/scheduler.py +184 -0
- solokit/work_items/spec_parser.py +838 -0
- solokit/work_items/spec_validator.py +493 -0
- solokit/work_items/updater.py +157 -0
- solokit/work_items/validator.py +205 -0
- solokit-0.1.1.dist-info/METADATA +640 -0
- solokit-0.1.1.dist-info/RECORD +323 -0
- solokit-0.1.1.dist-info/WHEEL +5 -0
- solokit-0.1.1.dist-info/entry_points.txt +2 -0
- solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
- solokit-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Integration test validation checker.
|
|
4
|
+
|
|
5
|
+
Validates integration test environment, documentation, and execution.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import time
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Union, cast
|
|
14
|
+
|
|
15
|
+
from solokit.core.command_runner import CommandRunner
|
|
16
|
+
from solokit.core.constants import DOCKER_COMMAND_TIMEOUT, QUALITY_CHECK_STANDARD_TIMEOUT
|
|
17
|
+
from solokit.core.exceptions import CommandExecutionError
|
|
18
|
+
from solokit.core.logging_config import get_logger
|
|
19
|
+
from solokit.core.types import WorkItemType
|
|
20
|
+
from solokit.quality.checkers.base import CheckResult, QualityChecker
|
|
21
|
+
from solokit.work_items import spec_parser
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class IntegrationChecker(QualityChecker):
|
|
27
|
+
"""Integration test requirements validation."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
work_item: dict[str, Any],
|
|
32
|
+
config: dict[str, Any],
|
|
33
|
+
runner: CommandRunner | None = None,
|
|
34
|
+
config_path: Path | None = None,
|
|
35
|
+
):
|
|
36
|
+
"""Initialize integration checker.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
work_item: Work item dictionary (must be integration_test type)
|
|
40
|
+
config: Integration test configuration
|
|
41
|
+
runner: Optional CommandRunner instance (for testing)
|
|
42
|
+
config_path: Path to full config file (for loading documentation settings)
|
|
43
|
+
"""
|
|
44
|
+
super().__init__(config)
|
|
45
|
+
self.work_item = work_item
|
|
46
|
+
self.runner = (
|
|
47
|
+
runner
|
|
48
|
+
if runner is not None
|
|
49
|
+
else CommandRunner(default_timeout=QUALITY_CHECK_STANDARD_TIMEOUT)
|
|
50
|
+
)
|
|
51
|
+
self.config_path = config_path if config_path is not None else Path(".session/config.json")
|
|
52
|
+
|
|
53
|
+
def name(self) -> str:
|
|
54
|
+
"""Return checker name."""
|
|
55
|
+
return "integration"
|
|
56
|
+
|
|
57
|
+
def is_enabled(self) -> bool:
|
|
58
|
+
"""Check if integration validation is enabled."""
|
|
59
|
+
return bool(self.config.get("enabled", True))
|
|
60
|
+
|
|
61
|
+
def run(self) -> CheckResult:
|
|
62
|
+
"""Execute integration test validation (full orchestration).
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
CheckResult with orchestrated validation outcome
|
|
66
|
+
"""
|
|
67
|
+
start_time = time.time()
|
|
68
|
+
|
|
69
|
+
# Only run for integration_test work items
|
|
70
|
+
if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
|
|
71
|
+
return self._create_skipped_result("not integration test")
|
|
72
|
+
|
|
73
|
+
if not self.is_enabled():
|
|
74
|
+
return self._create_skipped_result("disabled")
|
|
75
|
+
|
|
76
|
+
logger.info("Running integration test quality gates...")
|
|
77
|
+
|
|
78
|
+
results: dict[str, Any] = {
|
|
79
|
+
"integration_tests": {},
|
|
80
|
+
"performance_benchmarks": {},
|
|
81
|
+
"api_contracts": {},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
errors = []
|
|
85
|
+
warnings = []
|
|
86
|
+
|
|
87
|
+
# Import here to avoid circular imports
|
|
88
|
+
from solokit.core.exceptions import (
|
|
89
|
+
EnvironmentSetupError,
|
|
90
|
+
IntegrationExecutionError,
|
|
91
|
+
IntegrationTestError,
|
|
92
|
+
)
|
|
93
|
+
from solokit.testing.integration_runner import IntegrationTestRunner
|
|
94
|
+
|
|
95
|
+
runner_instance = IntegrationTestRunner(self.work_item)
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
# Setup environment (now raises exceptions instead of returning tuple)
|
|
99
|
+
runner_instance.setup_environment()
|
|
100
|
+
|
|
101
|
+
# Execute integration tests (now returns dict and raises exceptions on failure)
|
|
102
|
+
test_results = runner_instance.run_tests()
|
|
103
|
+
results["integration_tests"] = test_results
|
|
104
|
+
|
|
105
|
+
# Check if tests passed
|
|
106
|
+
if test_results.get("failed", 0) > 0:
|
|
107
|
+
logger.error("Integration tests failed")
|
|
108
|
+
errors.append(
|
|
109
|
+
{"message": f"{test_results.get('failed', 0)} integration tests failed"}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
logger.info(f"Integration tests passed ({test_results.get('passed', 0)} tests)")
|
|
113
|
+
|
|
114
|
+
# 2. Run performance benchmarks
|
|
115
|
+
if self.work_item.get("performance_benchmarks"):
|
|
116
|
+
from solokit.testing.performance import PerformanceBenchmark
|
|
117
|
+
|
|
118
|
+
benchmark = PerformanceBenchmark(self.work_item)
|
|
119
|
+
benchmarks_passed, benchmark_results = benchmark.run_benchmarks()
|
|
120
|
+
results["performance_benchmarks"] = benchmark_results
|
|
121
|
+
|
|
122
|
+
if not benchmarks_passed:
|
|
123
|
+
logger.error("Performance benchmarks failed")
|
|
124
|
+
if self.config.get("performance_benchmarks", {}).get("required", True):
|
|
125
|
+
errors.append({"message": "Performance benchmarks failed"})
|
|
126
|
+
else:
|
|
127
|
+
warnings.append({"message": "Performance benchmarks failed (optional)"})
|
|
128
|
+
else:
|
|
129
|
+
logger.info("Performance benchmarks passed")
|
|
130
|
+
|
|
131
|
+
# 3. Validate API contracts
|
|
132
|
+
if self.work_item.get("api_contracts"):
|
|
133
|
+
from solokit.quality.api_validator import APIContractValidator
|
|
134
|
+
|
|
135
|
+
validator = APIContractValidator(self.work_item)
|
|
136
|
+
contracts_passed, contract_results = validator.validate_contracts()
|
|
137
|
+
results["api_contracts"] = contract_results
|
|
138
|
+
|
|
139
|
+
if not contracts_passed:
|
|
140
|
+
logger.error("API contract validation failed")
|
|
141
|
+
if self.config.get("api_contracts", {}).get("required", True):
|
|
142
|
+
errors.append({"message": "API contract validation failed"})
|
|
143
|
+
else:
|
|
144
|
+
warnings.append({"message": "API contract validation failed (optional)"})
|
|
145
|
+
else:
|
|
146
|
+
logger.info("API contracts validated")
|
|
147
|
+
|
|
148
|
+
except (
|
|
149
|
+
EnvironmentSetupError,
|
|
150
|
+
IntegrationExecutionError,
|
|
151
|
+
IntegrationTestError,
|
|
152
|
+
) as e:
|
|
153
|
+
# Integration test setup or execution failed
|
|
154
|
+
logger.error(f"Integration test error: {e}")
|
|
155
|
+
errors.append({"message": str(e)})
|
|
156
|
+
|
|
157
|
+
finally:
|
|
158
|
+
# Always teardown environment
|
|
159
|
+
try:
|
|
160
|
+
runner_instance.teardown_environment()
|
|
161
|
+
except (OSError, CommandExecutionError) as e:
|
|
162
|
+
# Log teardown failures but don't fail the gate
|
|
163
|
+
logger.warning(f"Environment teardown failed: {e}")
|
|
164
|
+
warnings.append({"message": f"Environment teardown failed: {e}"})
|
|
165
|
+
|
|
166
|
+
execution_time = time.time() - start_time
|
|
167
|
+
passed = len(errors) == 0
|
|
168
|
+
|
|
169
|
+
return CheckResult(
|
|
170
|
+
checker_name=self.name(),
|
|
171
|
+
passed=passed,
|
|
172
|
+
status="passed" if passed else "failed",
|
|
173
|
+
errors=cast(list[Union[dict[str, Any], str]], errors),
|
|
174
|
+
warnings=cast(list[Union[dict[str, Any], str]], warnings),
|
|
175
|
+
info=results,
|
|
176
|
+
execution_time=execution_time,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def validate_environment(self) -> CheckResult:
|
|
180
|
+
"""Validate integration test environment requirements.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
CheckResult with environment validation outcome
|
|
184
|
+
"""
|
|
185
|
+
start_time = time.time()
|
|
186
|
+
|
|
187
|
+
if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
|
|
188
|
+
return self._create_skipped_result("not integration test")
|
|
189
|
+
|
|
190
|
+
env_requirements = self.work_item.get("environment_requirements", {})
|
|
191
|
+
results: dict[str, Any] = {
|
|
192
|
+
"docker_available": False,
|
|
193
|
+
"docker_compose_available": False,
|
|
194
|
+
"required_services": [],
|
|
195
|
+
"missing_config": [],
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
errors = []
|
|
199
|
+
|
|
200
|
+
# Check Docker available
|
|
201
|
+
result = self.runner.run(["docker", "--version"], timeout=DOCKER_COMMAND_TIMEOUT)
|
|
202
|
+
results["docker_available"] = result.success
|
|
203
|
+
|
|
204
|
+
if not result.success:
|
|
205
|
+
errors.append({"message": "Docker not available"})
|
|
206
|
+
|
|
207
|
+
# Check Docker Compose available
|
|
208
|
+
result = self.runner.run(["docker-compose", "--version"], timeout=DOCKER_COMMAND_TIMEOUT)
|
|
209
|
+
results["docker_compose_available"] = result.success
|
|
210
|
+
|
|
211
|
+
if not result.success:
|
|
212
|
+
errors.append({"message": "Docker Compose not available"})
|
|
213
|
+
|
|
214
|
+
# Check compose file exists
|
|
215
|
+
compose_file = env_requirements.get("compose_file", "docker-compose.integration.yml")
|
|
216
|
+
if not Path(compose_file).exists():
|
|
217
|
+
results["missing_config"].append(compose_file)
|
|
218
|
+
errors.append({"message": f"Missing compose file: {compose_file}"})
|
|
219
|
+
|
|
220
|
+
# Check config files exist
|
|
221
|
+
config_files = env_requirements.get("config_files", [])
|
|
222
|
+
for config_file in config_files:
|
|
223
|
+
if not Path(config_file).exists():
|
|
224
|
+
results["missing_config"].append(config_file)
|
|
225
|
+
errors.append({"message": f"Missing config file: {config_file}"})
|
|
226
|
+
|
|
227
|
+
execution_time = time.time() - start_time
|
|
228
|
+
passed = (
|
|
229
|
+
results["docker_available"]
|
|
230
|
+
and results["docker_compose_available"]
|
|
231
|
+
and len(results["missing_config"]) == 0
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return CheckResult(
|
|
235
|
+
checker_name=self.name(),
|
|
236
|
+
passed=passed,
|
|
237
|
+
status="passed" if passed else "failed",
|
|
238
|
+
errors=cast(list[Union[dict[str, Any], str]], errors),
|
|
239
|
+
warnings=[],
|
|
240
|
+
info=results,
|
|
241
|
+
execution_time=execution_time,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def validate_documentation(self) -> CheckResult:
|
|
245
|
+
"""Validate integration test documentation requirements.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
CheckResult with documentation validation outcome
|
|
249
|
+
"""
|
|
250
|
+
start_time = time.time()
|
|
251
|
+
|
|
252
|
+
if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
|
|
253
|
+
return self._create_skipped_result("not integration test")
|
|
254
|
+
|
|
255
|
+
# Get integration documentation config
|
|
256
|
+
full_config: dict[str, Any] = {}
|
|
257
|
+
if self.config_path.exists():
|
|
258
|
+
try:
|
|
259
|
+
with open(self.config_path) as f:
|
|
260
|
+
full_config = json.load(f)
|
|
261
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
262
|
+
logger.debug(f"Failed to load config: {e}")
|
|
263
|
+
|
|
264
|
+
config = full_config.get("integration_tests", {}).get("documentation", {})
|
|
265
|
+
if not config.get("enabled", True):
|
|
266
|
+
return self._create_skipped_result("documentation validation disabled")
|
|
267
|
+
|
|
268
|
+
results: dict[str, Any] = {"checks": [], "missing": []}
|
|
269
|
+
|
|
270
|
+
# 1. Check for integration architecture diagram
|
|
271
|
+
if config.get("architecture_diagrams", True):
|
|
272
|
+
diagram_paths = [
|
|
273
|
+
"docs/architecture/integration-architecture.md",
|
|
274
|
+
"docs/integration-architecture.md",
|
|
275
|
+
".session/specs/integration-architecture.md",
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
diagram_found = any(Path(p).exists() for p in diagram_paths)
|
|
279
|
+
results["checks"].append(
|
|
280
|
+
{"name": "Integration architecture diagram", "passed": diagram_found}
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if not diagram_found:
|
|
284
|
+
results["missing"].append("Integration architecture diagram")
|
|
285
|
+
|
|
286
|
+
# 2. Check for sequence diagrams (using spec_parser)
|
|
287
|
+
if config.get("sequence_diagrams", True):
|
|
288
|
+
# Parse spec file to get test scenarios
|
|
289
|
+
try:
|
|
290
|
+
parsed_spec = spec_parser.parse_spec_file(self.work_item)
|
|
291
|
+
scenarios = parsed_spec.get("test_scenarios", [])
|
|
292
|
+
except (OSError, ValueError, KeyError) as e:
|
|
293
|
+
logger.debug(f"Failed to parse spec file for scenarios: {e}")
|
|
294
|
+
scenarios = []
|
|
295
|
+
|
|
296
|
+
if scenarios:
|
|
297
|
+
# Check if any scenario content contains sequence diagrams
|
|
298
|
+
has_sequence = False
|
|
299
|
+
for scenario in scenarios:
|
|
300
|
+
content = scenario.get("content", "")
|
|
301
|
+
if "```mermaid" in content or "sequenceDiagram" in content:
|
|
302
|
+
has_sequence = True
|
|
303
|
+
break
|
|
304
|
+
|
|
305
|
+
results["checks"].append({"name": "Sequence diagrams", "passed": has_sequence})
|
|
306
|
+
|
|
307
|
+
if not has_sequence:
|
|
308
|
+
results["missing"].append("Sequence diagrams for test scenarios")
|
|
309
|
+
|
|
310
|
+
# 3. Check for API contract documentation (using spec_parser)
|
|
311
|
+
if config.get("contract_documentation", True):
|
|
312
|
+
# Parse spec file to get API contracts
|
|
313
|
+
try:
|
|
314
|
+
parsed_spec = spec_parser.parse_spec_file(self.work_item)
|
|
315
|
+
api_contracts = parsed_spec.get("api_contracts", "")
|
|
316
|
+
# API contracts should be documented in the spec
|
|
317
|
+
has_contracts = api_contracts and len(api_contracts.strip()) > 20
|
|
318
|
+
except (OSError, ValueError, KeyError) as e:
|
|
319
|
+
logger.debug(f"Failed to parse spec file for API contracts: {e}")
|
|
320
|
+
has_contracts = False
|
|
321
|
+
|
|
322
|
+
results["checks"].append(
|
|
323
|
+
{
|
|
324
|
+
"name": "API contracts documented",
|
|
325
|
+
"passed": has_contracts,
|
|
326
|
+
}
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
if not has_contracts:
|
|
330
|
+
results["missing"].append("API contract documentation")
|
|
331
|
+
|
|
332
|
+
# 4. Check for performance baseline documentation (using spec_parser)
|
|
333
|
+
if config.get("performance_baseline_docs", True):
|
|
334
|
+
# Parse spec file to get performance benchmarks
|
|
335
|
+
try:
|
|
336
|
+
parsed_spec = spec_parser.parse_spec_file(self.work_item)
|
|
337
|
+
benchmarks = parsed_spec.get("performance_benchmarks", "")
|
|
338
|
+
has_benchmarks = benchmarks and len(benchmarks.strip()) > 20
|
|
339
|
+
except (OSError, ValueError, KeyError) as e:
|
|
340
|
+
logger.debug(f"Failed to parse spec file for performance benchmarks: {e}")
|
|
341
|
+
has_benchmarks = False
|
|
342
|
+
|
|
343
|
+
if has_benchmarks:
|
|
344
|
+
baseline_file = Path(".session/tracking/performance_baselines.json")
|
|
345
|
+
baseline_exists = baseline_file.exists()
|
|
346
|
+
|
|
347
|
+
results["checks"].append(
|
|
348
|
+
{
|
|
349
|
+
"name": "Performance baseline documented",
|
|
350
|
+
"passed": baseline_exists,
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
if not baseline_exists:
|
|
355
|
+
results["missing"].append("Performance baseline documentation")
|
|
356
|
+
|
|
357
|
+
# 5. Check for integration point documentation (using spec_parser)
|
|
358
|
+
try:
|
|
359
|
+
parsed_spec = spec_parser.parse_spec_file(self.work_item.get("id"))
|
|
360
|
+
scope = parsed_spec.get("scope", "")
|
|
361
|
+
# Check if scope has meaningful content
|
|
362
|
+
documented = scope and len(scope.strip()) > 20
|
|
363
|
+
except (OSError, ValueError, KeyError) as e:
|
|
364
|
+
logger.debug(f"Failed to parse spec file for integration points: {e}")
|
|
365
|
+
documented = False
|
|
366
|
+
|
|
367
|
+
results["checks"].append({"name": "Integration points documented", "passed": documented})
|
|
368
|
+
|
|
369
|
+
if not documented:
|
|
370
|
+
results["missing"].append("Integration points documentation")
|
|
371
|
+
|
|
372
|
+
# Determine overall pass/fail
|
|
373
|
+
passed_checks = sum(1 for check in results["checks"] if check["passed"])
|
|
374
|
+
total_checks = len(results["checks"])
|
|
375
|
+
|
|
376
|
+
# Pass if all required checks pass
|
|
377
|
+
passed = len(results["missing"]) == 0
|
|
378
|
+
results["summary"] = f"{passed_checks}/{total_checks} documentation requirements met"
|
|
379
|
+
|
|
380
|
+
execution_time = time.time() - start_time
|
|
381
|
+
|
|
382
|
+
errors = []
|
|
383
|
+
for missing in results["missing"]:
|
|
384
|
+
errors.append({"message": f"Missing: {missing}"})
|
|
385
|
+
|
|
386
|
+
return CheckResult(
|
|
387
|
+
checker_name=self.name(),
|
|
388
|
+
passed=passed,
|
|
389
|
+
status="passed" if passed else "failed",
|
|
390
|
+
errors=cast(list[Union[dict[str, Any], str]], errors),
|
|
391
|
+
warnings=[],
|
|
392
|
+
info=results,
|
|
393
|
+
execution_time=execution_time,
|
|
394
|
+
)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Code linting checker.
|
|
4
|
+
|
|
5
|
+
Runs linters like ruff, flake8, eslint, etc.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import time
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Union, cast
|
|
13
|
+
|
|
14
|
+
from solokit.core.command_runner import CommandRunner
|
|
15
|
+
from solokit.core.constants import QUALITY_CHECK_VERY_LONG_TIMEOUT
|
|
16
|
+
from solokit.core.logging_config import get_logger
|
|
17
|
+
from solokit.quality.checkers.base import CheckResult, QualityChecker
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LintingChecker(QualityChecker):
|
|
23
|
+
"""Code linting validation."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config: dict[str, Any],
|
|
28
|
+
project_root: Path | None = None,
|
|
29
|
+
language: str | None = None,
|
|
30
|
+
auto_fix: bool | None = None,
|
|
31
|
+
runner: CommandRunner | None = None,
|
|
32
|
+
):
|
|
33
|
+
"""Initialize linting checker.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config: Linting configuration
|
|
37
|
+
project_root: Project root directory
|
|
38
|
+
language: Programming language (python, javascript, typescript)
|
|
39
|
+
auto_fix: Whether to automatically fix issues (overrides config)
|
|
40
|
+
runner: Optional CommandRunner instance (for testing)
|
|
41
|
+
"""
|
|
42
|
+
super().__init__(config, project_root)
|
|
43
|
+
self.runner = (
|
|
44
|
+
runner
|
|
45
|
+
if runner is not None
|
|
46
|
+
else CommandRunner(default_timeout=QUALITY_CHECK_VERY_LONG_TIMEOUT)
|
|
47
|
+
)
|
|
48
|
+
self.language = language or self._detect_language()
|
|
49
|
+
self.auto_fix = auto_fix if auto_fix is not None else self.config.get("auto_fix", False)
|
|
50
|
+
|
|
51
|
+
def name(self) -> str:
|
|
52
|
+
"""Return checker name."""
|
|
53
|
+
return "linting"
|
|
54
|
+
|
|
55
|
+
def is_enabled(self) -> bool:
|
|
56
|
+
"""Check if linting is enabled."""
|
|
57
|
+
return bool(self.config.get("enabled", True))
|
|
58
|
+
|
|
59
|
+
def _detect_language(self) -> str:
|
|
60
|
+
"""Detect primary project language."""
|
|
61
|
+
if (self.project_root / "pyproject.toml").exists() or (
|
|
62
|
+
self.project_root / "setup.py"
|
|
63
|
+
).exists():
|
|
64
|
+
return "python"
|
|
65
|
+
elif (self.project_root / "package.json").exists():
|
|
66
|
+
if (self.project_root / "tsconfig.json").exists():
|
|
67
|
+
return "typescript"
|
|
68
|
+
return "javascript"
|
|
69
|
+
return "python" # default
|
|
70
|
+
|
|
71
|
+
def run(self) -> CheckResult:
|
|
72
|
+
"""Run linting checks."""
|
|
73
|
+
start_time = time.time()
|
|
74
|
+
|
|
75
|
+
if not self.is_enabled():
|
|
76
|
+
return self._create_skipped_result()
|
|
77
|
+
|
|
78
|
+
logger.info(f"Running linting for {self.language}")
|
|
79
|
+
|
|
80
|
+
# Get linting command for language
|
|
81
|
+
commands = self.config.get("commands", {})
|
|
82
|
+
command = commands.get(self.language)
|
|
83
|
+
if not command:
|
|
84
|
+
logger.warning(f"No linting command configured for language: {self.language}")
|
|
85
|
+
return self._create_skipped_result(reason=f"no command for {self.language}")
|
|
86
|
+
|
|
87
|
+
# Add auto-fix flag if supported
|
|
88
|
+
if self.auto_fix:
|
|
89
|
+
if self.language == "python":
|
|
90
|
+
command += " --fix"
|
|
91
|
+
elif self.language in ["javascript", "typescript"]:
|
|
92
|
+
command += " --fix"
|
|
93
|
+
|
|
94
|
+
# Run linter
|
|
95
|
+
result = self.runner.run(command.split(), timeout=QUALITY_CHECK_VERY_LONG_TIMEOUT)
|
|
96
|
+
|
|
97
|
+
execution_time = time.time() - start_time
|
|
98
|
+
|
|
99
|
+
if result.timed_out:
|
|
100
|
+
required = self.config.get("required", False)
|
|
101
|
+
if required:
|
|
102
|
+
return CheckResult(
|
|
103
|
+
checker_name=self.name(),
|
|
104
|
+
passed=False,
|
|
105
|
+
status="failed",
|
|
106
|
+
errors=[{"message": "Linting timed out"}],
|
|
107
|
+
warnings=[],
|
|
108
|
+
info={"reason": "timeout"},
|
|
109
|
+
execution_time=execution_time,
|
|
110
|
+
)
|
|
111
|
+
return CheckResult(
|
|
112
|
+
checker_name=self.name(),
|
|
113
|
+
passed=True,
|
|
114
|
+
status="skipped",
|
|
115
|
+
errors=[],
|
|
116
|
+
warnings=[],
|
|
117
|
+
info={"reason": "timeout"},
|
|
118
|
+
execution_time=execution_time,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Tool not found
|
|
122
|
+
if result.returncode == -1:
|
|
123
|
+
required = self.config.get("required", False)
|
|
124
|
+
if required:
|
|
125
|
+
return CheckResult(
|
|
126
|
+
checker_name=self.name(),
|
|
127
|
+
passed=False,
|
|
128
|
+
status="failed",
|
|
129
|
+
errors=[{"message": "Required linting tool not found"}],
|
|
130
|
+
warnings=[],
|
|
131
|
+
info={"reason": "tool not found"},
|
|
132
|
+
execution_time=execution_time,
|
|
133
|
+
)
|
|
134
|
+
return self._create_skipped_result(reason="linting tool not available")
|
|
135
|
+
|
|
136
|
+
passed = result.returncode == 0
|
|
137
|
+
|
|
138
|
+
errors = []
|
|
139
|
+
if not passed:
|
|
140
|
+
errors.append(
|
|
141
|
+
{
|
|
142
|
+
"message": f"Linting found {result.returncode} issue(s)",
|
|
143
|
+
"output": result.stdout[:500] if result.stdout else "",
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return CheckResult(
|
|
148
|
+
checker_name=self.name(),
|
|
149
|
+
passed=passed,
|
|
150
|
+
status="passed" if passed else "failed",
|
|
151
|
+
errors=cast(list[Union[dict[str, Any], str]], errors),
|
|
152
|
+
warnings=[],
|
|
153
|
+
info={
|
|
154
|
+
"issues_found": result.returncode,
|
|
155
|
+
"auto_fixed": self.auto_fix,
|
|
156
|
+
"output": result.stdout[:1000] if result.stdout else "",
|
|
157
|
+
},
|
|
158
|
+
execution_time=execution_time,
|
|
159
|
+
)
|