feat: 1、流水线总开关配置 2、删除p0p1p2级别阻断
All checks were successful
Redis序列化结构检查 / redis-schema-check (push) Has been skipped
All checks were successful
Redis序列化结构检查 / redis-schema-check (push) Has been skipped
This commit is contained in:
@@ -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: []
|
||||||
|
|||||||
@@ -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 "首次提交,跳过检测"
|
||||||
|
|||||||
11
docs/实施方案.md
11
docs/实施方案.md
@@ -433,14 +433,11 @@ java -jar redis-schema-checker.jar \
|
|||||||
详见 `docs/配置说明.md`。核心开关:
|
详见 `docs/配置说明.md`。核心开关:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# 运行模式:notify(仅通知)| block(P0/P1/P2 全部阻断流水线)
|
# 总开关:false 时跳过检测与通知,流水线直接通过
|
||||||
mode: notify
|
enabled: true
|
||||||
|
|
||||||
# block 模式下触发 exit 1 的严重级别(全部阻断)
|
# 运行模式:notify(仅通知)| block(检测到结构变更即阻断流水线)
|
||||||
block_severities:
|
mode: notify
|
||||||
- P0
|
|
||||||
- P1
|
|
||||||
- P2
|
|
||||||
|
|
||||||
# 是否发送企微通知
|
# 是否发送企微通知
|
||||||
notify:
|
notify:
|
||||||
|
|||||||
37
docs/配置说明.md
37
docs/配置说明.md
@@ -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]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")));
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user