package com.codechecker.cache.cli; import com.codechecker.cache.analyze.SchemaCheckAnalyzer; import com.codechecker.cache.config.CheckerConfig; import com.codechecker.cache.config.ConfigLoader; import com.codechecker.cache.notify.WeComNotifier; import com.codechecker.cache.report.CheckReport; import com.codechecker.cache.report.ReportBuilder; import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import java.nio.file.Path; import java.util.List; import java.util.concurrent.Callable; /** * 命令行入口。退出码:0 通过 / 1 阻断 / 2 执行错误。 */ @Command(name = "serialization-schema-checker", mixinStandardHelpOptions = true, version = "serialization-schema-checker 1.0.0", description = "检测两次提交间缓存/MQ 等 value 序列化结构变更并通过企微机器人通知。") public class SerializationSchemaCheckerMain implements Callable { @Option(names = "--config", required = true, description = "业务仓库检测配置文件路径") private Path configPath; @Option(names = "--repo-root", required = true, description = "被检测仓库根目录") private Path repoRoot; @Option(names = "--old-sha", required = true, description = "对比基准提交") private String oldSha; @Option(names = "--new-sha", required = true, description = "当前提交") private String newSha; @Option(names = "--branch", description = "分支名(用于报告展示)") private String branch; @Option(names = "--modifier", description = "提交人") private String modifier; @Option(names = "--modify-time", description = "提交时间") private String modifyTime; @Option(names = "--repository", description = "仓库名(默认取仓库目录名)") private String repository; @Option(names = "--dry-run", description = "只输出报告,不发送企微通知") private boolean dryRun; @Override public Integer call() { try { CheckerConfig config = ConfigLoader.load(configPath); if (!config.isEnabled()) { System.out.println("[serialization-schema-checker] 总开关 enabled=false,跳过检测。"); return 0; } if (oldSha == null || oldSha.trim().isEmpty()) { System.out.println("[serialization-schema-checker] 无对比基准提交,跳过检测。"); return 0; } Path root = repoRoot.toAbsolutePath().normalize(); SchemaCheckAnalyzer analyzer = new SchemaCheckAnalyzer(config, root); CheckReport report = analyzer.analyze(oldSha, newSha); report.setBranch(branch); report.setModifier(modifier); report.setModifyTime(modifyTime); report.setRepository(repository != null ? repository : root.getFileName().toString()); ReportBuilder builder = new ReportBuilder(config.getNotify().getTitlePrefix()); System.out.println(builder.toConsole(report)); boolean shouldNotify = config.getNotify().isEnabled() && (report.hasChanges() || config.getNotify().isNotifyOnClean()); if (shouldNotify && !dryRun) { String webhook = config.getNotify().getWebhookUrl(); List messages = builder.toWeComMessages(report); int ok = new WeComNotifier().sendMarkdownMessages(webhook, messages); System.out.println("[serialization-schema-checker] 企微通知发送: " + ok + "/" + messages.size() + (messages.size() > 1 ? "(已按 key 拆分)" : "")); } if (report.isBlocked()) { System.out.println("[serialization-schema-checker] block 模式命中,流水线将被阻断(exit 1)。"); } return report.getExitCode(); } catch (Exception e) { System.err.println("[serialization-schema-checker] 执行错误: " + e.getMessage()); e.printStackTrace(); return 2; } } public static void main(String[] args) { int exitCode = new CommandLine(new SerializationSchemaCheckerMain()).execute(args); System.exit(exitCode); } }