feat: 1、流水线总开关配置 2、删除p0p1p2级别阻断
All checks were successful
Redis序列化结构检查 / redis-schema-check (push) Has been skipped

This commit is contained in:
2026-07-14 10:58:05 +08:00
parent 7a8ca7ce0b
commit 114b053733
10 changed files with 74 additions and 68 deletions

View File

@@ -5,27 +5,24 @@
# - 本配置文件为业务覆盖配置,会与 jar 内 default-config.yaml 深度合并 # - 本配置文件为业务覆盖配置,会与 jar 内 default-config.yaml 深度合并
# - 未声明的项沿用工具内置默认值(忽略规则、检测模式等) # - 未声明的项沿用工具内置默认值(忽略规则、检测模式等)
# 运行模式 notify-仅通知,不阻断流水线 block-按block_severities阻断流水线exit 1 # 总开关 true-执行检测 false-跳过检测
mode: notify enabled: true
# block 模式下触发阻断的严重级别P0/P1/P2 全部阻断 # 运行模式 notify-仅通知,不阻断流水线 block-检测到结构变更即阻断流水线exit 1
block_severities: mode: notify
- P0
- P1
- P2
# 通知配置 # 通知配置
notify: notify:
enabled: true enabled: true
webhook_url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=fa14f0b3-e01a-40f6-96bd-e18beb94e85e webhook_url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=fa14f0b3-e01a-40f6-96bd-e18beb94e85e
notify_on_clean: false notify_on_clean: false
title_prefix: "【Redis数据结构变更】" title_prefix: "【序列化结构变更】"
# 观察期:先只扫描 jnpf-tenant 模块,稳定后改为 include_modules: [] # 观察期:先只扫描 jnpf-tenant 模块,稳定后改为 include_modules: []
include_modules: include_modules:
- jnpf-tenant - jnpf-tenant
# 人工补充映射(自动推断不准时使用) # 手动补充映射(自动推断不准时使用)
manual_mappings: manual_mappings:
- id: tenant-db-content - id: tenant-db-content
writer_method: "jnpf.util.TenantDbContentCacheHelper#cacheSuccess" writer_method: "jnpf.util.TenantDbContentCacheHelper#cacheSuccess"
@@ -33,5 +30,5 @@ manual_mappings:
value_type: "jnpf.util.TenantDbContentCacheHelper.CacheEnvelope" value_type: "jnpf.util.TenantDbContentCacheHelper.CacheEnvelope"
description: "租户库信息缓存" description: "租户库信息缓存"
# 已知误报抑制(按需添加) # 误报忽略(按需添加)
suppressions: [] suppressions: []

View File

@@ -30,9 +30,19 @@ jobs:
echo "错误: 缺少 .gitea/config/redis-schema-check-config.yaml" echo "错误: 缺少 .gitea/config/redis-schema-check-config.yaml"
exit 1 exit 1
fi fi
# 顶层总开关 enabled: false 时跳过后续步骤(与 notify.enabled 区分,仅匹配行首)
if grep -Eq '^enabled:[[:space:]]*false([[:space:]]|#|$)' .gitea/config/redis-schema-check-config.yaml; then
echo "总开关 enabled=false跳过 Redis 结构检查"
touch /tmp/redis-schema-check.skip
fi
- name: 从 Nexus 私库下载 redis-schema-checker - name: 从 Nexus 私库下载 redis-schema-checker
run: | run: |
if [ -f /tmp/redis-schema-check.skip ]; then
echo "总开关已关闭,跳过下载"
exit 0
fi
GROUP_PATH="com/codechecker/redis-schema-checker" GROUP_PATH="com/codechecker/redis-schema-checker"
JAR_NAME="redis-schema-checker-${REDIS_SCHEMA_CHECKER_VERSION}.jar" JAR_NAME="redis-schema-checker-${REDIS_SCHEMA_CHECKER_VERSION}.jar"
JAR_URL="${REDIS_SCHEMA_CHECKER_REPO_URL}/${GROUP_PATH}/${REDIS_SCHEMA_CHECKER_VERSION}/${JAR_NAME}" JAR_URL="${REDIS_SCHEMA_CHECKER_REPO_URL}/${GROUP_PATH}/${REDIS_SCHEMA_CHECKER_VERSION}/${JAR_NAME}"
@@ -57,10 +67,19 @@ jobs:
- name: 验证 JDK - name: 验证 JDK
run: | run: |
if [ -f /tmp/redis-schema-check.skip ]; then
echo "总开关已关闭,跳过"
exit 0
fi
echo "Java: $(java -version 2>&1 | head -1)" echo "Java: $(java -version 2>&1 | head -1)"
- name: 执行 Redis 序列化结构检测 - name: 执行 Redis 序列化结构检测
run: | run: |
if [ -f /tmp/redis-schema-check.skip ]; then
echo "总开关已关闭,跳过检测"
exit 0
fi
OLD_SHA=$(git rev-parse HEAD~1 2>/dev/null || echo "") OLD_SHA=$(git rev-parse HEAD~1 2>/dev/null || echo "")
if [ -z "$OLD_SHA" ]; then if [ -z "$OLD_SHA" ]; then
echo "首次提交,跳过检测" echo "首次提交,跳过检测"

View File

@@ -433,14 +433,11 @@ java -jar redis-schema-checker.jar \
详见 `docs/配置说明.md`。核心开关: 详见 `docs/配置说明.md`。核心开关:
```yaml ```yaml
# 运行模式notify仅通知| blockP0/P1/P2 全部阻断流水线) # 总开关false 时跳过检测与通知,流水线直接通过
mode: notify enabled: true
# block 模式下触发 exit 1 的严重级别(全部阻断 # 运行模式notify仅通知| block检测到结构变更即阻断流水线
block_severities: mode: notify
- P0
- P1
- P2
# 是否发送企微通知 # 是否发送企微通知
notify: notify:

View File

@@ -38,7 +38,6 @@ include_modules:
- `detection.patterns`W01~W03 - `detection.patterns`W01~W03
- `ignore.key_patterns`(锁/计数器/token - `ignore.key_patterns`(锁/计数器/token
- `block_severities`P0/P1/P2
- `detection.min_confidence``max_field_depth` - `detection.min_confidence``max_field_depth`
--- ---
@@ -46,17 +45,14 @@ include_modules:
## 2. 业务仓完整配置示例 ## 2. 业务仓完整配置示例
```yaml ```yaml
# 总开关false 时不执行检测、不发通知、流水线直接通过
enabled: true
# 运行模式 # 运行模式
# notify - 仅通知,不阻断流水线 # notify - 仅通知,不阻断流水线
# block - 按 block_severities 阻断流水线exit 1 # block - 检测到结构变更即阻断流水线exit 1
mode: notify mode: notify
# block 模式下触发 exit 1 的严重级别全部阻断P0/P1/P2
block_severities:
- P0
- P1
- P2
# 是否扫描测试代码(已确认:不扫描) # 是否扫描测试代码(已确认:不扫描)
scan_test_sources: false scan_test_sources: false
@@ -146,25 +142,28 @@ include_modules:
## 3. 配置项说明 ## 3. 配置项说明
### 3.1 mode ### 3.1 enabled
总开关。默认 `true`
| 值 | 行为 |
|----|------|
| `true` | 正常执行检测(再按 `mode` / `notify` 行为) |
| `false` | 跳过检测与通知,流水线 `exit 0`(与 `notify.enabled` 无关) |
临时关闭时可仅改此项,无需删除 workflow。
### 3.2 mode
| 值 | 行为 | | 值 | 行为 |
|----|------| |----|------|
| `notify` | 检测到变更 → 发企微 → `exit 0` | | `notify` | 检测到变更 → 发企微 → `exit 0` |
| `block` | 检测到 `block_severities` 中的级别 → 发企微 → `exit 1` | | `block` | 检测到任意结构变更 → 发企微 → `exit 1` |
### 3.2 block_severities
默认 `["P0", "P1", "P2"]``block` 模式下任意级别变更均 `exit 1`
建议上线初期仍使用 `mode: notify` 观察误报情况,确认稳定后再切换: 建议上线初期仍使用 `mode: notify` 观察误报情况,确认稳定后再切换:
```yaml ```yaml
mode: block mode: block
block_severities:
- P0
- P1
- P2
``` ```
### 3.3 notify ### 3.3 notify
@@ -280,7 +279,6 @@ include_modules:
```yaml ```yaml
mode: block mode: block
block_severities: [P0, P1, P2]
include_modules: [] # 扩至全仓 include_modules: [] # 扩至全仓
``` ```
@@ -288,7 +286,6 @@ include_modules: [] # 扩至全仓
```yaml ```yaml
mode: block mode: block
block_severities: [P0, P1, P2]
include_modules: [] # 空表示全部模块 include_modules: [] # 空表示全部模块
detection: detection:
patterns: [W01, W02, W03, W04, W05] patterns: [W01, W02, W03, W04, W05]

View File

@@ -330,16 +330,7 @@ public class SchemaCheckAnalyzer {
report.getChanges().addAll(changes); report.getChanges().addAll(changes);
report.getKeyChanges().addAll(keyChanges.values()); report.getKeyChanges().addAll(keyChanges.values());
boolean blocked = false; boolean blocked = config.isBlockMode() && !changes.isEmpty();
if (config.isBlockMode()) {
Set<String> blockSev = new HashSet<>(config.getBlockSeverities());
for (SchemaChange c : changes) {
if (blockSev.contains(c.getSeverity().name())) {
blocked = true;
break;
}
}
}
report.setBlocked(blocked); report.setBlocked(blocked);
report.setExitCode(blocked ? 1 : 0); report.setExitCode(blocked ? 1 : 0);
return report; return report;

View File

@@ -55,6 +55,11 @@ public class RedisSchemaCheckerMain implements Callable<Integer> {
try { try {
CheckerConfig config = ConfigLoader.load(configPath); CheckerConfig config = ConfigLoader.load(configPath);
if (!config.isEnabled()) {
System.out.println("[redis-schema-checker] 总开关 enabled=false跳过检测。");
return 0;
}
if (oldSha == null || oldSha.trim().isEmpty()) { if (oldSha == null || oldSha.trim().isEmpty()) {
System.out.println("[redis-schema-checker] 无对比基准提交,跳过检测。"); System.out.println("[redis-schema-checker] 无对比基准提交,跳过检测。");
return 0; return 0;

View File

@@ -10,11 +10,12 @@ import java.util.Map;
*/ */
public class CheckerConfig { public class CheckerConfig {
/** 总开关false 时跳过检测与通知(流水线 exit 0 */
private boolean enabled = true;
/** notify | block */ /** notify | block */
private String mode = "notify"; private String mode = "notify";
private List<String> blockSeverities = new ArrayList<>();
private boolean scanTestSources = false; private boolean scanTestSources = false;
private List<String> sourceRoots = new ArrayList<>(); private List<String> sourceRoots = new ArrayList<>();
@@ -231,6 +232,14 @@ public class CheckerConfig {
} }
} }
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getMode() { public String getMode() {
return mode; return mode;
} }
@@ -239,14 +248,6 @@ public class CheckerConfig {
this.mode = mode; this.mode = mode;
} }
public List<String> getBlockSeverities() {
return blockSeverities;
}
public void setBlockSeverities(List<String> blockSeverities) {
this.blockSeverities = blockSeverities;
}
public boolean isScanTestSources() { public boolean isScanTestSources() {
return scanTestSources; return scanTestSources;
} }

View File

@@ -75,8 +75,8 @@ public final class ConfigLoader {
private static CheckerConfig bind(Map<String, Object> map) { private static CheckerConfig bind(Map<String, Object> map) {
CheckerConfig config = new CheckerConfig(); CheckerConfig config = new CheckerConfig();
config.setEnabled(bool(map, "enabled", true));
config.setMode(str(map, "mode", "notify")); config.setMode(str(map, "mode", "notify"));
config.setBlockSeverities(strList(map.get("block_severities")));
config.setScanTestSources(bool(map, "scan_test_sources", false)); config.setScanTestSources(bool(map, "scan_test_sources", false));
config.setSourceRoots(strList(map.get("source_roots"))); config.setSourceRoots(strList(map.get("source_roots")));
config.setIncludeModules(strList(map.get("include_modules"))); config.setIncludeModules(strList(map.get("include_modules")));

View File

@@ -1,14 +1,11 @@
# redis-schema-checker 内置默认配置 # redis-schema-checker 内置默认配置
# 业务仓库通过 --config 指定的配置会与本文件深度合并(业务配置优先)。 # 业务仓库通过 --config 指定的配置会与本文件深度合并(业务配置优先)。
# 运行模式notify仅通知| block按 block_severities 阻断exit 1 # 总开关false 时不执行检测、不发通知、流水线直接通过
mode: notify enabled: true
# block 模式下触发阻断的严重级别(默认全部阻断 # 运行模式notify仅通知| block检测到结构变更即阻断exit 1
block_severities: mode: notify
- P0
- P1
- P2
# 是否扫描测试代码(第一版固定 false # 是否扫描测试代码(第一版固定 false
scan_test_sources: false scan_test_sources: false

View File

@@ -16,8 +16,8 @@ class ConfigLoaderTest {
@Test @Test
void loadsDefaultsWhenNoBusinessConfig() { void loadsDefaultsWhenNoBusinessConfig() {
CheckerConfig config = ConfigLoader.load(null); CheckerConfig config = ConfigLoader.load(null);
assertTrue(config.isEnabled());
assertEquals("notify", config.getMode()); assertEquals("notify", config.getMode());
assertTrue(config.getBlockSeverities().contains("P0"));
assertTrue(config.getDetection().getPatterns().contains("W01")); assertTrue(config.getDetection().getPatterns().contains("W01"));
assertFalse(config.isScanTestSources()); assertFalse(config.isScanTestSources());
} }
@@ -25,18 +25,20 @@ class ConfigLoaderTest {
@Test @Test
void businessConfigOverridesDefaults(@org.junit.jupiter.api.io.TempDir Path tmp) throws IOException { void businessConfigOverridesDefaults(@org.junit.jupiter.api.io.TempDir Path tmp) throws IOException {
Path cfg = tmp.resolve("biz.yaml"); Path cfg = tmp.resolve("biz.yaml");
Files.write(cfg, ("mode: block\n" Files.write(cfg, ("enabled: false\n"
+ "mode: block\n"
+ "include_modules:\n - jnpf-tenant\n" + "include_modules:\n - jnpf-tenant\n"
+ "notify:\n enabled: false\n").getBytes(StandardCharsets.UTF_8)); + "notify:\n enabled: false\n").getBytes(StandardCharsets.UTF_8));
CheckerConfig config = ConfigLoader.load(cfg); CheckerConfig config = ConfigLoader.load(cfg);
assertFalse(config.isEnabled());
assertEquals("block", config.getMode()); assertEquals("block", config.getMode());
assertTrue(config.isBlockMode()); assertTrue(config.isBlockMode());
assertEquals(1, config.getIncludeModules().size()); assertEquals(1, config.getIncludeModules().size());
assertEquals("jnpf-tenant", config.getIncludeModules().get(0)); assertEquals("jnpf-tenant", config.getIncludeModules().get(0));
// 未覆盖项保留默认 // 未覆盖项保留默认
assertFalse(config.getNotify().isEnabled()); assertFalse(config.getNotify().isEnabled());
assertTrue(config.getBlockSeverities().contains("P2")); assertTrue(config.getDetection().getPatterns().contains("W01"));
} }
@Test @Test