Spec-Kit 工具链实战
Spec-Kit 是一套规范相关的工具链。如何自动化验证规范?如何生成文档?本文详解 Spec-Kit 工具链的使用与实战。
一、Spec-Kit 概述
1.1 工具组成
Spec-Kit 工具链:
┌─────────────────────────────────────┐
│ spec-validator │
│ - Schema 验证 │
│ - 规范符合性检查 │
│ - 错误报告 │
├─────────────────────────────────────┤
│ spec-generator │
│ - 代码生成 │
│ - 文档生成 │
│ - 测试生成 │
├─────────────────────────────────────┤
│ spec-linter │
│ - 代码风格检查 │
│ - 规范一致性检查 │
│ - 最佳实践建议 │
├─────────────────────────────────────┤
│ spec-docs │
│ - API 文档生成 │
│ - 数据字典生成 │
│ - 示例代码生成 │
└─────────────────────────────────────┘
1.2 安装配置
# 安装 Spec-Kit
pip install spec-kit
# 初始化项目
spec-kit init
# 配置文件
# .speckit.yaml
version: 1.0
spec_dir: ./specs
output_dir: ./generated
rules:
- name: required-fields
enabled: true
- name: naming-convention
enabled: true
二、规范验证
2.1 Schema 验证
# spec_validation.py
from spec_kit import SpecValidator
from spec_kit.rules import RequiredFieldsRule, NamingConventionRule
class SpecValidationExample:
"""规范验证实例"""
def __init__(self):
self.validator = SpecValidator()
self._setup_rules()
def _setup_rules(self):
"""设置验证规则"""
# 必填字段规则
self.validator.add_rule(
RequiredFieldsRule(
fields=['name', 'version', 'description'],
error_message="Missing required field: {field}"
)
)
# 命名规范规则
self.validator.add_rule(
NamingConventionRule(
pattern=r'^[a-z][a-z0-9-]*$',
error_message="Invalid naming format: {name}"
)
)
def validate_spec(self, spec_path: str) -> Dict:
"""验证规范文件"""
result = self.validator.validate(spec_path)
return {
'valid': result.is_valid,
'errors': result.errors,
'warnings': result.warnings,
'info': result.info
}
def validate_batch(self, spec_paths: List[str]) -> Dict:
"""批量验证"""
results = []
for path in spec_paths:
result = self.validate_spec(path)
results.append({
'file': path,
**result
})
# 汇总统计
total = len(results)
valid = sum(1 for r in results if r['valid'])
invalid = total - valid
total_errors = sum(len(r['errors']) for r in results)
return {
'summary': {
'total': total,
'valid': valid,
'invalid': invalid,
'total_errors': total_errors
},
'details': results
}
# 使用示例
validator = SpecValidationExample()
# 验证单个文件
result = validator.validate_spec('./specs/user_api.yaml')
print(f"Valid: {result['valid']}")
print(f"Errors: {result['errors']}")
# 批量验证
batch_result = validator.validate_batch([
'./specs/user_api.yaml',
'./specs/product_api.yaml',
'./specs/order_api.yaml'
])
print(f"Summary: {batch_result['summary']}")
2.2 规范符合性检查
# compliance_check.py
from spec_kit import ComplianceChecker
from spec_kit.checks import APICheck, DataCheck, SecurityCheck
class ComplianceCheckExample:
"""符合性检查实例"""
def __init__(self):
self.checker = ComplianceChecker()
self._setup_checks()
def _setup_checks(self):
"""设置检查项"""
# API 检查
self.checker.add_check(
APICheck(
name='restful-compliance',
description='Check RESTful API compliance',
checks=[
'uses_http_methods_correctly',
'uses_nouns_not_verbs',
'version_in_url'
]
)
)
# 数据检查
self.checker.add_check(
DataCheck(
name='data-model-compliance',
description='Check data model compliance',
checks=[
'has_primary_key',
'has_timestamps',
'uses_standard_types'
]
)
)
# 安全检查
self.checker.add_check(
SecurityCheck(
name='security-compliance',
description='Check security compliance',
checks=[
'requires_authentication',
'uses_https',
'validates_input'
]
)
)
def check_compliance(self, spec_path: str) -> Dict:
"""检查符合性"""
result = self.checker.check(spec_path)
return {
'overall_score': result.score,
'checks': {
check.name: {
'passed': check.passed,
'score': check.score,
'issues': check.issues
}
for check in result.checks
}
}
# 使用示例
checker = ComplianceCheckExample()
result = checker.check_compliance('./specs/api.yaml')
print(f"Overall Score: {result['overall_score']}%")
for check_name, check_result in result['checks'].items():
status = "✓" if check_result['passed'] else "✗"
print(f"{status} {check_name}: {check_result['score']}%")
三、代码生成
3.1 模型代码生成
# code_generation.py
from spec_kit import CodeGenerator
from spec_kit.templates import PythonModelTemplate, TypeScriptModelTemplate
class CodeGenerationExample:
"""代码生成实例"""
def __init__(self):
self.generator = CodeGenerator()
self._register_templates()
def _register_templates(self):
"""注册模板"""
# Python 模型模板
self.generator.register_template(
'python_model',
PythonModelTemplate()
)
# TypeScript 模型模板
self.generator.register_template(
'typescript_model',
TypeScriptModelTemplate()
)
def generate_models(
self,
spec_path: str,
output_dir: str,
language: str
) -> Dict:
"""生成模型代码"""
result = self.generator.generate(
template=f'{language}_model',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'errors': result.errors
}
def generate_api_client(
self,
spec_path: str,
output_dir: str,
language: str
) -> Dict:
"""生成 API 客户端"""
result = self.generator.generate(
template=f'{language}_client',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'errors': result.errors
}
# 使用示例
generator = CodeGenerationExample()
# 生成 Python 模型
result = generator.generate_models(
spec_path='./specs/models.yaml',
output_dir='./generated/python/models',
language='python'
)
print(f"Generated files: {result['files']}")
# 生成 TypeScript 客户端
result = generator.generate_api_client(
spec_path='./specs/api.yaml',
output_dir='./generated/typescript/client',
language='typescript'
)
print(f"Generated files: {result['files']}")
3.2 测试代码生成
# test_generation.py
from spec_kit import TestGenerator
from spec_kit.templates import UnitTestTemplate, IntegrationTestTemplate
class TestGenerationExample:
"""测试生成实例"""
def __init__(self):
self.generator = TestGenerator()
self._register_templates()
def _register_templates(self):
"""注册模板"""
# 单元测试模板
self.generator.register_template(
'unit_test',
UnitTestTemplate()
)
# 集成测试模板
self.generator.register_template(
'integration_test',
IntegrationTestTemplate()
)
def generate_unit_tests(
self,
spec_path: str,
output_dir: str,
framework: str = 'pytest'
) -> Dict:
"""生成单元测试"""
result = self.generator.generate(
template=f'{framework}_unit_test',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'test_count': result.test_count,
'errors': result.errors
}
def generate_integration_tests(
self,
spec_path: str,
output_dir: str,
framework: str = 'pytest'
) -> Dict:
"""生成集成测试"""
result = self.generator.generate(
template=f'{framework}_integration_test',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'test_count': result.test_count,
'errors': result.errors
}
# 使用示例
test_generator = TestGenerationExample()
# 生成单元测试
result = test_generator.generate_unit_tests(
spec_path='./specs/models.yaml',
output_dir='./tests/unit',
framework='pytest'
)
print(f"Generated {result['test_count']} unit tests")
# 生成集成测试
result = test_generator.generate_integration_tests(
spec_path='./specs/api.yaml',
output_dir='./tests/integration',
framework='pytest'
)
print(f"Generated {result['test_count']} integration tests")
四、文档生成
4.1 API 文档生成
# doc_generation.py
from spec_kit import DocGenerator
from spec_kit.templates import APIDocTemplate, ModelDocTemplate
class DocGenerationExample:
"""文档生成实例"""
def __init__(self):
self.generator = DocGenerator()
self._register_templates()
def _register_templates(self):
"""注册模板"""
# API 文档模板
self.generator.register_template(
'api_doc',
APIDocTemplate()
)
# 模型文档模板
self.generator.register_template(
'model_doc',
ModelDocTemplate()
)
def generate_api_docs(
self,
spec_path: str,
output_dir: str,
format: str = 'markdown'
) -> Dict:
"""生成 API 文档"""
result = self.generator.generate(
template=f'api_doc_{format}',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'endpoints_documented': result.endpoints_count,
'errors': result.errors
}
def generate_model_docs(
self,
spec_path: str,
output_dir: str,
format: str = 'markdown'
) -> Dict:
"""生成模型文档"""
result = self.generator.generate(
template=f'model_doc_{format}',
spec_path=spec_path,
output_dir=output_dir
)
return {
'success': result.success,
'files': result.files,
'models_documented': result.models_count,
'errors': result.errors
}
def generate_complete_docs(
self,
specs_dir: str,
output_dir: str,
format: str = 'html'
) -> Dict:
"""生成完整文档"""
result = self.generator.generate_site(
specs_dir=specs_dir,
output_dir=output_dir,
format=format,
options={
'include_examples': True,
'include_schemas': True,
'theme': 'default'
}
)
return {
'success': result.success,
'files': result.files,
'pages': result.pages_count,
'errors': result.errors
}
# 使用示例
doc_generator = DocGenerationExample()
# 生成 API 文档
result = doc_generator.generate_api_docs(
spec_path='./specs/api.yaml',
output_dir='./docs/api',
format='markdown'
)
print(f"Documented {result['endpoints_documented']} endpoints")
# 生成完整文档站点
result = doc_generator.generate_complete_docs(
specs_dir='./specs',
output_dir='./docs/site',
format='html'
)
print(f"Generated {result['pages']} pages")
4.2 数据字典生成
# data_dictionary.py
from spec_kit import DataDictionaryGenerator
class DataDictionaryExample:
"""数据字典生成实例"""
def __init__(self):
self.generator = DataDictionaryGenerator()
def generate_dictionary(
self,
specs_dir: str,
output_path: str,
format: str = 'markdown'
) -> Dict:
"""生成数据字典"""
result = self.generator.generate(
specs_dir=specs_dir,
output_path=output_path,
format=format,
options={
'include_relationships': True,
'include_constraints': True,
'include_examples': True
}
)
return {
'success': result.success,
'tables': result.tables_count,
'fields': result.fields_count,
'errors': result.errors
}
def generate_erd(
self,
specs_dir: str,
output_path: str,
format: str = 'png'
) -> Dict:
"""生成实体关系图"""
result = self.generator.generate_erd(
specs_dir=specs_dir,
output_path=output_path,
format=format
)
return {
'success': result.success,
'entities': result.entities_count,
'relationships': result.relationships_count,
'file': result.output_file
}
# 使用示例
dict_generator = DataDictionaryExample()
# 生成数据字典
result = dict_generator.generate_dictionary(
specs_dir='./specs/models',
output_path='./docs/data_dictionary.md',
format='markdown'
)
print(f"Documented {result['tables']} tables, {result['fields']} fields")
# 生成 ERD
result = dict_generator.generate_erd(
specs_dir='./specs/models',
output_path='./docs/erd.png',
format='png'
)
print(f"Generated ERD with {result['entities']} entities")
五、CI/CD 集成
5.1 GitHub Actions
# .github/workflows/spec-validation.yml
name: Spec Validation
on:
push:
paths:
- 'specs/**'
pull_request:
paths:
- 'specs/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Spec-Kit
run: pip install spec-kit
- name: Validate Specs
run: spec-kit validate ./specs --output report.json
- name: Upload Report
uses: actions/upload-artifact@v3
with:
name: validation-report
path: report.json
- name: Check Compliance
run: spec-kit check ./specs --min-score 80
- name: Generate Code
run: spec-kit generate --specs ./specs --output ./generated
- name: Generate Docs
run: spec-kit docs --specs ./specs --output ./docs
generate:
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v3
- name: Install Spec-Kit
run: pip install spec-kit
- name: Generate Models
run: spec-kit generate models --specs ./specs --output ./src/models
- name: Generate Tests
run: spec-kit generate tests --specs ./specs --output ./tests
- name: Commit Generated Files
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: 'Auto-generate from specs'
file_pattern: 'src/models/* tests/*'
5.2 质量门禁
# quality_gates.py
from spec_kit import QualityGate
class QualityGatesExample:
"""质量门禁实例"""
def __init__(self):
self.gate = QualityGate()
self._setup_gates()
def _setup_gates(self):
"""设置质量门禁"""
# 验证通过率门禁
self.gate.add_gate(
name='validation_pass_rate',
check=lambda result: result['pass_rate'] >= 0.95,
error_message="Validation pass rate must be >= 95%"
)
# 符合性分数门禁
self.gate.add_gate(
name='compliance_score',
check=lambda result: result['score'] >= 80,
error_message="Compliance score must be >= 80"
)
# 测试覆盖率门禁
self.gate.add_gate(
name='test_coverage',
check=lambda result: result['coverage'] >= 0.80,
error_message="Test coverage must be >= 80%"
)
# 文档完整率门禁
self.gate.add_gate(
name='documentation_completeness',
check=lambda result: result['completeness'] >= 0.90,
error_message="Documentation must be >= 90% complete"
)
def check_quality(self, results: Dict) -> Dict:
"""检查质量"""
result = self.gate.check(results)
return {
'passed': result.passed,
'failed_gates': result.failed_gates,
'details': result.details
}
# 使用示例
quality = QualityGatesExample()
result = quality.check_quality({
'pass_rate': 0.98,
'score': 85,
'coverage': 0.85,
'completeness': 0.92
})
if result['passed']:
print("✓ All quality gates passed")
else:
print("✗ Quality gates failed:")
for gate in result['failed_gates']:
print(f" - {gate}")
六、总结
6.1 核心要点
-
规范验证
- Schema 验证
- 符合性检查
- 批量验证
-
代码生成
- 模型代码
- 测试代码
- API 客户端
-
文档生成
- API 文档
- 数据字典
- 完整站点
6.2 最佳实践
-
自动化
- CI/CD 集成
- 自动验证
- 自动生成
-
质量门禁
- 验证通过率
- 符合性分数
- 测试覆盖率
-
持续改进
- 定期审查
- 规则更新
- 工具升级
参考资料