semver-analyzerSkill semver-analyzer

semver-analyzer是一个专门分析代码变更并确定适当语义版本更新的技能,确保一致的SDK版本控制和清晰地向消费者传达变更影响。关键词包括:语义版本控制、自动检测破坏性变更、版本更新建议、变更日志生成、版本一致性验证。

DevOps 0 次安装 0 次浏览 更新于 2/26/2026

semver-analyzer

分析代码变更并确定语义版本更新。自动检测破坏性变更,建议版本更新(主版本/次版本/补丁),生成变更日志条目,并验证版本一致性。

允许使用的工具:Bash(*) 读写编辑 Grep WebFetch 元数据: 作者:babysitter-sdk 版本:“1.0.0” 类别:版本兼容性 待办事项ID:SK-SDK-004

semver-analyzer

你是 semver-analyzer - 一个专门分析代码变更并确定适当语义版本更新的技能,确保一致的SDK版本控制和清晰地向消费者传达变更影响。

概览

这项技能支持AI驱动的语义版本控制,包括:

  • 自动检测破坏性变更
  • 建议版本更新(主版本/次版本/补丁)
  • 从提交生成变更日志条目
  • 在SDK之间验证版本一致性
  • 强制执行传统提交标准
  • 自动创建发布说明
  • 跟踪版本依赖关系

前提条件

  • 带有版本历史的Git仓库
  • 传统提交消息(推荐)
  • 包清单文件(package.json, pyproject.toml等)
  • semantic-release或类似工具(可选)

能力

1. 破坏性变更检测

自动检测SDK代码中的破坏性变更:

// src/analyzer/breaking-changes.ts
import { parse } from '@typescript-eslint/parser';
import { diff } from 'deep-object-diff';

接口 BreakingChange {
  type: 'removed' | 'signature-changed' | 'type-changed' | 'behavior-changed';
  location: 字符串;
  description: 字符串;
  severity: 'major' | 'warning';
  migration?: 字符串;
}

接口 AnalysisResult {
  hasBreakingChanges: 布尔值;
  breakingChanges: BreakingChange[];
  suggestedBump: 'major' | 'minor' | 'patch';
  confidence: 数字;
}

export async 函数 analyzeChanges(
  oldVersion: 字符串,
  newVersion: 字符串,
  options: AnalyzerOptions
): Promise<AnalysisResult> {
  常量 oldApi = 等待 extractPublicApi(oldVersion);
  常量 newApi = 等待 extractPublicApi(newVersion);

  常量 breakingChanges: BreakingChange[] = [];

  // 检查已移除的导出
  对于 (常量 [name, oldExport] of Object.entries(oldApi.exports)) {
    如果 (!(name in newApi.exports)) {
      breakingChanges.push({
        type: 'removed',
        location: 名字,
        description: `导出 '${name}' 已被移除`,
        severity: 'major',
        migration: `移除 '${name}' 的使用或使用替代品`
      });
    }
  }

  // 检查函数签名变更
  对于 (常量 [name, newFunc] of Object.entries(newApi.functions)) {
    常量 oldFunc = oldApi.functions[name];
    如果 (!oldFunc) 继续;

    // 检查参数变更
    如果 (newFunc.requiredParams > oldFunc.requiredParams) {
      breakingChanges.push({
        type: 'signature-changed',
        location: 名字,
        description: `函数 '${name}' 有新的必需参数`,
        severity: 'major',
        migration: `更新对 '${name}' 的调用以包含新的必需参数`
      });
    }

    // 检查返回类型变更
    如果 (newFunc.returnType !== oldFunc.returnType) {
      如果 (!isTypeCompatible(oldFunc.returnType, newFunc.returnType)) {
        breakingChanges.push({
          type: 'type-changed',
          location: 名字,
          description: `函数 '${name}' 的返回类型从 '${oldFunc.returnType}' 变更为 '${newFunc.returnType}'`,
          severity: 'major'
        });
      }
    }
  }

  // 检查模型中的类型变更
  对于 (常量 [name, newModel] of Object.entries(newApi.models)) {
    常量 oldModel = oldApi.models[name];
    如果 (!oldModel) 继续;

    // 检查已移除的字段
    对于 (常量 field of Object.keys(oldModel.fields)) {
      如果 (!(field in newModel.fields)) {
        breakingChanges.push({
          type: 'removed',
          location: `${name}.${field}`,
          description: `字段 '${field}' 已从模型 '${name}' 中移除`,
          severity: 'major'
        });
      }
    }

    // 检查字段类型变更
    对于 (常量 [field, newField] of Object.entries(newModel.fields)) {
      常量 oldField = oldModel.fields[field];
      如果 (oldField && oldField.type !== newField.type) {
        breakingChanges.push({
          type: 'type-changed',
          location: `${name}.${field}`,
          description: `字段 '${name}.${field}' 类型从 '${oldField.type}' 变更为 '${newField.type}'`,
          severity: 'major'
        });
      }
    }
  }

  常量 hasBreakingChanges = breakingChanges.length > 0;

  返回 {
    hasBreakingChanges,
    breakingChanges,
    suggestedBump: hasBreakingChanges ? 'major' : 等待 analyzeFeaturesAndFixes(oldVersion, newVersion),
    confidence: calculateConfidence(breakingChanges)
  };
}

2. 传统提交分析

解析和分析传统提交:

// src/analyzer/commits.ts
import { execSync } from 'child_process';

接口 CommitInfo {
  hash: 字符串;
  type: 字符串;
  scope?: 字符串;
  description: 字符串;
  body?: 字符串;
  breaking: 布尔值;
  footers: 记录<string, 字符串>;
}

接口 CommitAnalysis {
  commits: CommitInfo[];
  suggestedBump: 'major' | 'minor' | 'patch';
  changelog: ChangelogSection[];
}

常量 COMMIT_PATTERN = /^(?<type>\w+)(?:\((?<scope>[^)]+)\))?(?<breaking>!)?: (?<description>.+)$/;

export 函数 analyzeCommits(fromRef: 字符串, toRef: 字符串): CommitAnalysis {
  常量 log = execSync(
      `git log ${fromRef}..${toRef} --format="%H|||%s|||%b|||%N" --no-merges`,
      { encoding: 'utf8' }
  );

  常量 commits: CommitInfo[] = [];
  让 suggestedBump: 'major' | 'minor' | 'patch' = 'patch';

  对于 (常量 entry of log.split('
').filter(Boolean)) {
    常量 [hash, subject, body, notes] = entry.split('|||');
    常量 match = COMMIT_PATTERN.exec(subject);

    如果 (!match?.groups) 继续;

    常量 commit: CommitInfo = {
      hash,
      type: match.groups.type,
      scope: match.groups.scope,
      description: match.groups.description,
      body: body?.trim(),
      breaking: match.groups.breaking === '!' || body?.includes('BREAKING CHANGE:'),
      footers: parseFooters(body)
    };

    commits.push(commit);

    // 确定版本更新
    如果 (commit.breaking) {
      suggestedBump = 'major';
    } 否则如果 (commit.type === 'feat' && suggestedBump !== 'major') {
      suggestedBump = 'minor';
    }
  }

  返回 {
    commits,
    suggestedBump,
    changelog: generateChangelog(commits)
  };
}

函数 parseFooters(body?: 字符串): 记录<string, 字符串> {
  如果 (!body) 返回 {};

  常量 footers: 记录<string, 字符串> = {};
  常量 lines = body.split('
');

  对于 (常量 line of lines) {
    常量 match = /^(?<key>[\w-]+): (?<value>.+)$/.exec(line);
    如果 (match?.groups) {
      footers[match.groups.key] = match.groups.value;
    }
  }

  返回 footers;
}

函数 generateChangelog(commits: CommitInfo[]): ChangelogSection[] {
  常量 sections: 记录<string, CommitInfo[]> = {
    'Breaking Changes': [],
    'Features': [],
    'Bug Fixes': [],
    'Performance': [],
    'Documentation': [],
    'Other': []
  };

  对于 (常量 commit of commits) {
    如果 (commit.breaking) {
      sections['Breaking Changes'].push(commit);
    }

    开关 (commit.type) {
      案例 'feat':
        sections['Features'].push(commit);
        打破;
      案例 'fix':
        sections['Bug Fixes'].push(commit);
        打破;
      案例 'perf':
        sections['Performance'].push(commit);
        打破;
      案例 'docs':
        sections['Documentation'].push(commit);
        打破;
      默认:
        sections['Other'].push(commit);
    }
  }

  返回 Object.entries(sections)
    .filter(([_, commits]) => commits.length > 0)
    .map(([标题, commits]) => ({
      标题,
      项目: commits.map(c => ({
        scope: c.scope,
        description: c.description,
        hash: c.hash.substring(0, 7)
      }))
    }));
}

3. 语义发布配置

配置语义发布以自动化版本控制:

// release.config.js
module.exports = {
  branches: [
    'main',
    { name: 'beta', prerelease: true },
    { name: 'alpha', prerelease: true }
  ],
  plugins: [
    ['@semantic-release/commit-analyzer', {
      preset: 'conventionalcommits',
      releaseRules: [
        { type: 'feat', release: 'minor' },
        { type: 'fix', release: 'patch' },
        { type: 'perf', release: 'patch' },
        { type: 'refactor', release: 'patch' },
        { type: 'docs', scope: 'api', release: 'patch' },
        { breaking: true, release: 'major' }
      ],
      parserOpts: {
        noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING']
      }
    }],
    ['@semantic-release/release-notes-generator', {
      preset: 'conventionalcommits',
      presetConfig: {
        types: [
          { type: 'feat', section: 'Features' },
          { type: 'fix', section: 'Bug Fixes' },
          { type: 'perf', section: 'Performance' },
          { type: 'refactor', section: 'Code Refactoring' },
          { type: 'docs', section: 'Documentation' },
          { type: 'chore', hidden: true }
        ]
      }
    }],
    ['@semantic-release/changelog', {
      changelogFile: 'CHANGELOG.md'
    }],
    ['@semantic-release/npm'],
    ['@semantic-release/git', {
      assets: ['CHANGELOG.md', 'package.json'],
      message: 'chore(release): ${nextRelease.version} [skip ci]

${nextRelease.notes}'
    }],
    ['@semantic-release/github']
  ]
};

4. 版本一致性验证

验证SDK实现之间的版本一致性:

// src/validator/version-consistency.ts
import { readFileSync } from 'fs';
import semver from 'semver';

接口 SDKVersion {
  语言: 字符串;
  版本: 字符串;
  路径: 字符串;
}

接口 ValidationResult {
  isConsistent: 布尔值;
  版本: SDKVersion[];
  问题: ValidationIssue[];
  建议: 字符串;
}

export 函数 validateVersionConsistency(
  sdkPaths: 记录<string, 字符串>
): ValidationResult {
  常量 versions: SDKVersion[] = [];
  常量 issues: ValidationIssue[] = [];

  // 从每个SDK提取版本
  对于 (常量 [language, basePath] of Object.entries(sdkPaths)) {
    常量 version = extractVersion(language, basePath);
    versions.push({ 语言, 版本, 路径: basePath });
  }

  // 检查一致性
  常量 uniqueVersions = 新 Set(versions.map(v => v.version));

  如果 (uniqueVersions.size > 1) {
    issues.push({
      类型: 'version-mismatch',
      消息: `SDKs有不同的版本:${Array.from(uniqueVersions).join(', ')}`,
      严重性: 'error'
    });
  }

  // 检查semver有效性
  对于 (常量 { 语言, 版本 } of versions) {
    如果 (!semver.valid(version)) {
      issues.push({
        类型: 'invalid-semver',
        消息: `${语言} SDK有无效的semver:${版本}`,
        严重性: 'error'
      });
    }
  }

  // 检查预发布一致性
  常量 prereleases = versions.filter(v => semver.prerelease(v.version));
  常量 releases = versions.filter(v => !semver.prerelease(v.version));

  如果 (prereleases.length > 0 && releases.length > 0) {
    issues.push({
      类型: 'prerelease-mismatch',
      消息: '一些SDK是预发布版本,而其他不是',
      严重性: 'warning'
    });
  }

  返回 {
    isConsistent: issues.filter(i => i.severity === 'error').length === 0,
    版本,
    问题,
    建议: generateRecommendation(versions, issues)
  };
}

函数 extractVersion(language: 字符串, basePath: 字符串): 字符串 {
  开关 (language) {
    案例 'typescript':
    案例 'javascript': {
      常量 pkg = JSON.parse(readFileSync(`${basePath}/package.json`, 'utf8'));
      返回 pkg.version;
    }
    案例 'python': {
      常量 toml = readFileSync(`${basePath}/pyproject.toml`, 'utf8');
      常量 match = /version\s*=\s*"([^"]+)"/.exec(toml);
      返回 match?.[1] ?? '0.0.0';
    }
    案例 'java': {
      常量 pom = readFileSync(`${basePath}/pom.xml`, 'utf8');
      常量 match = /<version>([^<]+)<\/version>/.exec(pom);
      返回 match?.[1] ?? '0.0.0';
    }
    案例 'go': {
      // Go模块使用git标签,检查go.mod
      常量 mod = readFileSync(`${basePath}/go.mod`, 'utf8');
      // 版本通常来自git标签
      返回 getLatestGitTag(basePath);
    }
    默认:
      抛出新 Error(`不支持的语言:${language}`);
  }
}

5. 变更日志生成

生成全面的变更日志:

// src/changelog/generator.ts
import { analyzeCommits } from '../analyzer/commits';

接口 Changelog选项 {
  版本: 字符串;
  日期: 字符串;
  从Ref: 字符串;
  到Ref: 字符串;
  仓库Url?: 字符串;
  includeCommitLinks?: 布尔值;
}

export 函数 generateChangelog(options: Changelog选项): 字符串 {
  常量 analysis = analyzeCommits(options.fromRef, options.toRef);
  常量 lines: 字符串[] = [];

  lines.push(`## [${options.version}](${options.repositoryUrl}/compare/${options.fromRef}...${options.toRef}) (${options.date})`);
  lines.push('');

  对于 (常量 section of analysis.changelog) {
    lines.push(`### ${section.title}`);
    lines.push('');

    对于 (常量 item of section.items) {
      常量 scope = item.scope ? `**${item.scope}:** ` : '';
      常量 link = options.includeCommitLinks && options.repositoryUrl
        ? ` ([${item.hash}](${options.repositoryUrl}/commit/${item.hash}))`
        : '';

      lines.push(`* ${scope}${item.description}${link}`);
    }

    lines.push('');
  }

  返回 lines.join('
');
}

// 示例输出:
// ## [2.0.0](https://github.com/org/sdk/compare/v1.5.0...v2.0.0) (2026-01-24)
//
// ### Breaking Changes
//
// * **api:** 移除弃用的getUsers方法 ([abc1234](https://github.com/org/sdk/commit/abc1234))
//
// ### Features
//
// * **users:** 添加批量操作 ([def5678](https://github.com/org/sdk/commit/def5678))
// * **orders:** 实现分页支持 ([ghi9012](https://github.com/org/sdk/commit/ghi9012))
//
// ### Bug Fixes
//
// * **auth:** 修复令牌刷新竞态条件 ([jkl3456](https://github.com/org/sdk/commit/jkl3456))

6. 版本更新自动化

跨SDK自动化版本更新:

// src/automation/bump.ts
import { execSync } from 'child_process';
import semver from 'semver';

接口 Bump选项 {
  sdkPaths: 记录<string, 字符串>;
  更新类型: 'major' | 'minor' | 'patch' | 'prerelease';
  预发布标签?: 字符串;
  干运行?: 布尔值;
}

export 异步 函数 bumpVersions(options: Bump选项): Promise<Bump结果> {
  常量 results: 记录<string, { 旧: 字符串; 新: 字符串 }> = {};

  // 获取当前版本
  常量 currentVersions = getVersions(options.sdkPaths);

  // 计算新版本(以TypeScript SDK为基准)
  常量 baseVersion = currentVersions['typescript'];
  常量 newVersion = semver.inc(
    baseVersion,
    options.bumpType,
    options.prereleaseTag
  );

  如果 (!newVersion) {
    抛出新 Error(`无法从 ${baseVersion} 计算新版本`);
  }

  如果 (options.dryRun) {
    console.log(`[DRY RUN] 将把所有SDK更新到 ${newVersion}`);
    返回 { 干运行: 真, 新版本, 更改: {} };
  }

  // 更新每个SDK
  对于 (常量 [language, path] of Object.entries(options.sdkPaths)) {
    常量 oldVersion = currentVersions[language];
    updateVersion(language, path, newVersion);
    results[language] = { 旧: oldVersion, 新: newVersion };
  }

  返回 {
    干运行: 假,
    新版本,
    更改: results
  };
}

函数 updateVersion(language: 字符串, basePath: 字符串, version: 字符串): 空 {
  开关 (language) {
    案例 'typescript':
      execSync(`npm version ${version} --no-git-tag-version`, { cwd: basePath });
      打破;

    案例 'python':
      // 更新pyproject.toml
      常量 tomlPath = `${basePath}/pyproject.toml`;
      常量 toml = readFileSync(tomlPath, 'utf8');
      常量 updated = toml.replace(/version\s*=\s*"[^"]+"/, `version = "${version}"`);
      writeFileSync(tomlPath, updated);
      打破;

    案例 'java':
      execSync(`mvn versions:set -DnewVersion=${version}`, { cwd: basePath });
      打破;

    案例 'go':
      // Go版本来自git标签
      execSync(`git tag v${version}`, { cwd: basePath });
      打破;
  }
}

7. CI/CD集成

GitHub Actions工作流以进行版本控制:

名称:版本分析

on:
  pull_request:
    分支:[main]
  push:
    分支:[main]

作业:
  分析:
    运行在:ubuntu-latest
    步骤:
      - 使用:actions/checkout@v4
        带有:
          获取深度:0

      - 名称:设置Node.js
        使用:actions/setup-node@v4
        带有:
          node-version: '20'

      - 名称:安装依赖项
        运行:npm ci

      - 名称:分析变更
        id: analyze
        运行: |
          结果=$(node scripts/analyze-version.js)
          回声 "bump_type=$(echo $result | jq -r '.suggestedBump')" >> $GITHUB_OUTPUT
          回声 "has_breaking=$(echo $result | jq -r '.hasBreakingChanges')" >> $GITHUB_OUTPUT

      - 名称:在PR上评论
        如果:github.event_name == 'pull_request'
        使用:actions/github-script@v7
        带有:
          脚本: |
            常量 bumpType = '${{ steps.analyze.outputs.bump_type }}';
            常量 hasBreaking = '${{ steps.analyze.outputs.has_breaking }}';

            常量 body = `## 版本分析

            **建议的版本更新:** \`${bumpType}\``
            **有破坏性变更:** ${hasBreaking}

            ${hasBreaking === 'true' ? '⚠️ 此PR包含破坏性变更,将需要主版本更新。' : ''}
            `;

            github.rest.issues.createComment({
              所有者:context.repo.owner,
              仓库:context.repo.repo,
              问题编号:context.issue.number,
              正文
            });

  发布:
    如果:github.event_name == 'push' && github.ref == 'refs/heads/main'
    需要:analyze
    运行在:ubuntu-latest
    步骤:
      - 使用:actions/checkout@v4
        带有:
          获取深度:0

      - 名称:设置Node.js
        使用:actions/setup-node@v4
        带有:
          node-version: '20'

      - 名称:安装依赖项
        运行:npm ci

      - 名称:语义发布
        环境:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        运行:npx semantic-release

MCP服务器集成

这项技能可以利用以下MCP服务器:

服务器 描述 安装
changelog-generator 从提交生成变更日志 ComposioHQ
Specmatic MCP 检测破坏性变更 GitHub

最佳实践

  1. 传统提交 - 使用标准提交格式
  2. 自动化发布 - 使用semantic-release
  3. 版本锁定SDKs - 保持所有SDK版本同步
  4. 记录破坏性变更 - 清晰的迁移指南
  5. 预发布版本 - 用于测试的beta/alpha
  6. 保护主线 - 需要PR审查
  7. CI验证 - 自动分析版本
  8. 变更日志自动化 - 从提交生成

流程集成

这项技能与以下流程集成:

  • sdk-versioning-release-management.js - 发布工作流
  • backward-compatibility-management.js - 破坏性变更
  • api-versioning-strategy.js - API版本对齐
  • package-distribution.js - 发布发布

输出格式

{
  "operation": "analyze",
  "currentVersion": "1.5.0",
  "suggestedVersion": "2.0.0",
  "suggestedBump": "major",
  "hasBreakingChanges": 真,
  "breakingChanges": [
    {
      "type": "removed",
      "location": "UsersApi.getUsers",
      "description": "方法getUsers已被移除",
      "migration": "使用list()代替"
    }
  ],
  "commits": {
    "features": 3,
    "fixes": 5,
    "breaking": 1
  },
  "changelogPreview": "## [2.0.0] - 2026-01-24

### Breaking Changes
..."
}

错误处理

  • 验证semver格式
  • 处理缺失版本文件
  • 报告无效提交格式
  • 警告版本不一致
  • 支持回滚场景

约束

  • 需要git历史访问
  • 推荐传统提交
  • 多语言SDK需要同步
  • 破坏性变更需要协调
  • 预发布需要清晰的标记