Skip to content
清晨的一缕阳光
返回

Spec-Kit 工具链实战

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 核心要点

  1. 规范验证

    • Schema 验证
    • 符合性检查
    • 批量验证
  2. 代码生成

    • 模型代码
    • 测试代码
    • API 客户端
  3. 文档生成

    • API 文档
    • 数据字典
    • 完整站点

6.2 最佳实践

  1. 自动化

    • CI/CD 集成
    • 自动验证
    • 自动生成
  2. 质量门禁

    • 验证通过率
    • 符合性分数
    • 测试覆盖率
  3. 持续改进

    • 定期审查
    • 规则更新
    • 工具升级

参考资料


分享这篇文章到:

上一篇文章
Kafka Streams 高级应用实战
下一篇文章
Redis 性能监控与诊断