Compare commits

...

22 Commits

Author SHA1 Message Date
MerCry 00f4e0cd1a Merge branch 'main' into feat/multi-channel-framework
PR Check (SDD Full Gate) / sdd-full-gate (pull_request) Failing after 3s Details
2026-02-24 03:51:01 +00:00
MerCry 667a362596 Merge pull request '修改初始配置文件 适配gitea[AC-INIT]' (#11) from setup-gate into main
Reviewed-on: MerCry/ai-robot#11
2026-02-24 03:10:33 +00:00
MerCry 23e98cf50b 修改初始配置文件 适配gitea[AC-INIT]
PR Check (SDD Full Gate) / sdd-full-gate (pull_request) Successful in 3s Details
2026-02-24 11:10:08 +08:00
MerCry 9e24731400 Merge pull request '修改初始配置文件 适配gitea[AC-INIT]' (#10) from setup-gate into main
Reviewed-on: MerCry/ai-robot#10
2026-02-24 02:51:08 +00:00
MerCry d929f952cf 修改初始配置文件 适配gitea[AC-INIT]
PR Check (SDD Full Gate) / sdd-full-gate (pull_request) Successful in 3s Details
2026-02-24 10:50:39 +08:00
MerCry 6ad817f190 Merge pull request '修改初始配置文件 适配gitea[AC-INIT]' (#9) from setup-gate into main
Reviewed-on: MerCry/ai-robot#9
2026-02-24 02:44:31 +00:00
MerCry 5133d574a4 修改初始配置文件 适配gitea[AC-INIT]
PR Check (SDD Full Gate) / sdd-full-gate (pull_request) Failing after 2s Details
2026-02-24 10:43:10 +08:00
MerCry 474f27d4b8 Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#7) from setup-gate into main
Reviewed-on: MerCry/ai-robot#7
2026-02-23 15:38:04 +00:00
MerCry a21444634c chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Successful in 3s Details
2026-02-23 23:37:13 +08:00
MerCry c035d4b7b4 chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Successful in 3s Details
2026-02-23 23:16:03 +08:00
MerCry 132f1ffecb chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Failing after 2s Details
2026-02-23 23:11:58 +08:00
MerCry 52f5178758 Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#6) from setup-gate into main
Reviewed-on: MerCry/ai-robot#6
2026-02-23 15:10:39 +00:00
MerCry 3e33cbd710 chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Failing after 3s Details
2026-02-23 23:10:20 +08:00
MerCry 151b497403 Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#5) from setup-gate into main
Reviewed-on: MerCry/ai-robot#5
2026-02-23 15:04:05 +00:00
MerCry 465c049d0f chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Failing after 2s Details
2026-02-23 23:03:31 +08:00
MerCry 8a0df0b67e Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#4) from setup-gate into main
Reviewed-on: MerCry/ai-robot#4
2026-02-23 14:28:15 +00:00
MerCry 6eb0dd2754 chore: setup openapi contract gate [AC-INIT]
PR Check (SDD Contract Gate) / contract-level-check (pull_request) Has been cancelled Details
2026-02-23 22:27:43 +08:00
MerCry 57caadaa6f Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#3) from setup-gate into main
Reviewed-on: http://ashai.com.cn:3005/MerCry/ai-robot/pulls/3
2026-02-23 14:22:11 +00:00
MerCry cca754acd4 chore: setup openapi contract gate [AC-INIT] 2026-02-23 22:21:39 +08:00
MerCry e2604e812e Merge pull request 'chore: setup openapi contract gate [AC-INIT]' (#2) from setup-gate into main
Reviewed-on: http://ashai.com.cn:3005/MerCry/ai-robot/pulls/2
2026-02-23 14:17:26 +00:00
MerCry fc8197f6d5 chore: setup openapi contract gate [AC-INIT] 2026-02-23 22:16:37 +08:00
MerCry 2eb644173e feat: test openapi gate with L1 level [AC-TEST] 2026-02-23 22:08:31 +08:00
8 changed files with 437 additions and 6 deletions

View File

@ -0,0 +1,108 @@
name: PR Check (SDD Full Gate)
on:
pull_request:
branches: [ main ]
paths:
- '.gitea/workflows/**'
- 'scripts/**'
- 'spec/**'
- 'src/**'
- 'test/**'
jobs:
sdd-full-gate:
runs-on: ubuntu-latest
steps:
- name: Checkout code (no GitHub dependency)
shell: sh
run: |
set -eu
SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}"
REPO_NAME="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}"
COMMIT_SHA="${GITHUB_SHA:-${GITEA_SHA:-}}"
: "${SERVER_URL:?Could not determine SERVER_URL}"
: "${REPO_NAME:?Could not determine REPO_NAME}"
: "${COMMIT_SHA:?Could not determine COMMIT_SHA}"
echo "Using SERVER_URL=$SERVER_URL"
echo "Using REPO_NAME=$REPO_NAME"
echo "Using COMMIT_SHA=$COMMIT_SHA"
if [ -d ".git" ]; then
echo "Repo already initialized in workspace; using fetch"
git remote set-url origin "$SERVER_URL/$REPO_NAME.git"
else
git clone "$SERVER_URL/$REPO_NAME.git" .
fi
# 关键:不要把 main fetch 到本地分支 main会冲突
git fetch origin main:refs/remotes/origin/main
git fetch --depth=1 origin "$COMMIT_SHA"
git checkout -f "$COMMIT_SHA"
- name: 1. Commit Message Check
shell: sh
run: |
echo "Checking commit messages for [AC-...] or [TASK-...] (range: refs/remotes/origin/main..HEAD)"
# refs/remotes/origin/main is fetched in the checkout step
git log --no-merges --format=%B refs/remotes/origin/main..HEAD | cat
if git log --no-merges --format=%B refs/remotes/origin/main..HEAD | grep -Eq '\[(AC|TASK)-'; then
echo "OK: Found [AC-...] or [TASK-...] in PR commits"
else
echo "ERROR: At least one commit message in the PR must contain [AC-...] or [TASK-...]"
exit 1
fi
- name: 2. OpenAPI Contract Level Check
env:
REQUIRE_PROVIDER_L2: "1"
shell: sh
run: |
chmod +x scripts/*.sh
./scripts/check-openapi-level.sh
- name: 3. AC Traceability Check
shell: sh
run: ./scripts/check-traceability.sh
- name: 4. OpenAPI Breaking Change Check
shell: sh
run: ./scripts/check-openapi-diff.sh
- name: 5. Minimum Self-Test (mvn test)
shell: sh
run: |
# 针对 Java Spring 项目运行最小单测 (方案 B: 不存在则提示跳过)
if command -v mvn >/dev/null 2>&1; then
# 处理本地 jar 依赖:如果 lib 目录下存在 jar 包,先安装到本地仓库
if [ -f "lib/commons-codec-1.9.jar" ]; then
echo "Installing local jar: lib/commons-codec-1.9.jar"
mvn -q install:install-file \
-Dfile=lib/commons-codec-1.9.jar \
-DgroupId=commons-codec \
-DartifactId=commons-codec \
-Dversion=1.9 \
-Dpackaging=jar \
-DgeneratePom=true
fi
mvn -q -DskipTests=false test
else
echo "Warning: mvn not found, skipping unit tests. Please ensure Runner has JDK/Maven for full enforcement."
fi
- name: YAML Parse Check (Optional)
shell: sh
run: |
if command -v python3 >/dev/null 2>&1; then
if ! python3 -c "import yaml" 2>/dev/null; then
python3 -m pip install pyyaml --user >/dev/null 2>&1 || true
fi
if python3 -c "import yaml" 2>/dev/null; then
find spec -name "*.yaml" -o -name "*.yml" | xargs -I {} python3 -c "import yaml; yaml.safe_load(open('{}'))"
echo "YAML check passed."
fi
fi

View File

@ -1,3 +1,3 @@
# ai-robot # ai-robot
测试改动
ai机器人 ai机器人

View File

@ -125,13 +125,25 @@
- OpenAPI diff 检查通过(无未声明 breaking change - OpenAPI diff 检查通过(无未声明 breaking change
- 需求追踪检查通过AC 引用未断裂) - 需求追踪检查通过AC 引用未断裂)
### 6.3 推荐的实现位置(Git ### 6.3 推荐的实现位置Gitea 避坑建议
- **服务端 hooks最终防线** > **重要Gitea 环境下的 Hooks 优先级与冲突处理**
- `pre-receive` / `update`:拒绝不符合 main 硬门禁的 push
- `post-receive`:触发构建/测试/契约校验/(可选)自动合并流程
> 注:具体脚本实现(如何解析 OpenAPI、如何做 diff、如何跑契约测试属于工程实现细节建议以仓库内脚本`scripts/`)承载,并在 CI/构建中复用。 - **优先使用 Gitea 分支保护Branch Protection**
- 进入 `仓库设置 -> 分支 -> 保护分支(main)`
- 勾选 `禁止直接推送`:这是实现“禁推 main”最稳定、最标准的方式。
- 勾选 `允许由 PR 合并`:确保协作流程通畅。
- **避坑提示**:不要在服务端 `pre-receive` 钩子中一刀切地通过 `refs/heads/main` 拒绝所有更新。因为 Gitea 服务端的 PR 合并操作也会触发此钩子,导致 PR 无法合入。
- **服务端 Hookspre-receive职责收敛**
- 仅用于做“极轻量”的全局硬约束(如文件大小、非 utf-8 检查)。
- 不建议在 hook 里跑 Maven/JDK 等重型构建,否则会严重拖慢 push 速度并导致超时。
- **Gitea Actions / CI推荐的门禁位置**
- 这是落地“provider >= L2”和“契约测试”的最佳位置。
- 将校验脚本(如 `scripts/check-openapi-level.sh`)集成进 Action。
- 在保护分支设置中勾选 `要求通过状态检查后才允许合并`
- **环境搭建详见**`docs/setup-gitea-actions-gate.md`包含新环境部署、Runner 配置与离线环境优化)。
--- ---

View File

@ -0,0 +1,74 @@
# GiteaDocker落地分支保护 + Actions/Runner + OpenAPI 全量门禁(操作手册)
本文档用于在**新环境/新机器**上从零落地本仓库的“规范驱动 + 接口先行”门禁体系,确保换环境后无需重新摸索。
---
## 0. 目标与产物
落地后应满足:
- [ ] `main` 禁止直接 push仅允许 PR 合并
- [ ] PR 合并到 `main` 时自动运行 Actions全量门禁
- [ ] 环境无法访问 GitHub 时也能正常运行校验
仓库内相关文件(必须存在于 `main`
- `agents.md`AI 编码总纲
- `spec/contracting.md`:契约标准
- `scripts/*.sh`核心校验脚本Level/Traceability/Diff
- `.gitea/workflows/pr-check.yaml`:全量门禁工作流
---
## 1. Gitea Actions 基础建设
按照 `docs/setup-gitea-actions-gate.md` 中的步骤完成:
1. **Gitea 配置**:在 `app.ini` 中启用 `[ACTIONS] ENABLED = true`
2. **Runner 部署**:启动 `gitea/act_runner:latest` 容器并成功注册到 Gitea。
3. **内网连接**:使用宿主机内网 IP 作为 `GITEA_INSTANCE_URL`
---
## 2. 启用全量自动化门禁
### 2.1 门禁项列表
当前的 `.gitea/workflows/pr-check.yaml` (Job ID: `sdd-full-gate`) 包含以下检查:
| 门禁项 | 脚本位置 | 检查逻辑 | 失败处理 |
| :--- | :--- | :--- | :--- |
| **1. 契约成熟度** | `check-openapi-level.sh` | 校验 `info.x-contract-level`。合并 main 必须 ≥ L2。 | AI 需更新 OpenAPI 文件等级。 |
| **2. 需求追踪** | `check-traceability.sh` | 校验代码中的 `[AC-ID]` 是否在 `requirements.md` 中定义过。 | AI 需补充需求文档或修正代码注释。 |
| **3. Breaking Change** | `check-openapi-diff.sh` | 对比 `main` 分支,拦截被删除的 Endpoint 或 Method。 | AI 需还原破坏性变更或与人类确认。 |
| **4. 最小自测** | 内置命令 | 执行 `mvn test`Java。若 Runner 环境无 mvn 则跳过并提示。 | AI 需修复单测或编译错误。 |
### 2.2 在 Gitea 中开启硬约束
1. **触发第一次运行**:新建一个 PR 到 `main`(修改 `src/``spec/` 下的文件)。
2. **配置分支保护**
* 进入 `仓库设置 -> 分支 -> 保护分支(main)`
* 勾选 **“启用状态检查”**。
* 在输入框中填入:`sdd-full-gate`。
* 保存。
---
## 3. 常见排障与优化
### 3.1 离线环境报错
如果报错 `GITEA_SERVER_URL is required`,请确认已合并最新的 `.gitea/workflows/pr-check.yaml`。当前版本已支持自动探测 `GITHUB_``GITEA_` 系列变量。
### 3.2 Maven (mvn) 找不到
如果日志提示 `Warning: mvn not found`,说明你的 Runner 镜像ubuntu-latest没有预装 Maven。
* **短期**:脚本会自动跳过,不阻断合并。
* **长期建议**:定制 Docker 镜像或在宿主机安装 Maven 并卷入容器。
### 3.3 Python yaml 模块缺失
脚本会自动尝试 `pip install pyyaml`。如果依然失败YAML 语法解析步骤将自动跳过,不影响核心契约校验。
---
## 4. 关联文档入口
- `agents.md`AI 实时遵循的提交与编码节奏。
- `docs/contracting-guide.md`:契约治理与 Gitea 避坑指南。
- `docs/session-handoff-protocol.md`:复杂任务接续协议。

View File

@ -0,0 +1,77 @@
#!/usr/bin/env sh
set -eu
# OpenAPI Breaking Change Detector (Minimal Script).
# 1. Compare the PR's openapi.provider.yaml with the version from the 'main' branch.
# 2. Detect basic breaking changes (deleted endpoints, changed methods, etc.)
# 3. Fail if breaking changes are found without explicit developer acknowledgement.
# Base branch to compare against
BASE_BRANCH="refs/remotes/origin/main"
die() {
echo "ERROR: $*" >&2
exit 1
}
# Create a temporary directory for main branch files
tmp_base=$(mktemp -d)
trap 'rm -rf "$tmp_base"' EXIT
check_breaking_changes() {
module_path="$1"
provider_file="spec/$module_path/openapi.provider.yaml"
base_file="$tmp_base/$module_path/openapi.provider.yaml"
[ -f "$provider_file" ] || return 0
# Try to extract the file from the base branch
mkdir -p "$(dirname "$base_file")"
if ! git show "$BASE_BRANCH:$provider_file" > "$base_file" 2>/dev/null; then
echo "New module or provider file detected: $provider_file. Skipping diff check."
return 0
fi
echo "Checking breaking changes for $provider_file against $BASE_BRANCH..."
# 1. Simple Endpoint/Method deletion check using grep/diff
# Extract paths and methods (simple grep for ' /path:' and ' get|post|put|delete:')
extract_endpoints() {
grep -E "^[[:space:]]{2}/|^[[:space:]]{4}(get|post|put|delete|patch):" "$1" | sed 's/[[:space:]]*//g'
}
old_endpoints=$(mktemp)
new_endpoints=$(mktemp)
extract_endpoints "$base_file" > "$old_endpoints"
extract_endpoints "$provider_file" > "$new_endpoints"
deleted_count=$(comm -23 "$old_endpoints" "$new_endpoints" | wc -l)
if [ "$deleted_count" -gt 0 ]; then
echo "CRITICAL: Detected deleted endpoints or methods in $provider_file:"
comm -23 "$old_endpoints" "$new_endpoints"
rm -f "$old_endpoints" "$new_endpoints"
return 1
fi
rm -f "$old_endpoints" "$new_endpoints"
echo "OK: No obvious breaking changes in $provider_file endpoints."
return 0
}
# Find modules
errors=0
for spec_dir in spec/*; do
if [ -d "$spec_dir" ]; then
module_name=$(basename "$spec_dir")
if ! check_breaking_changes "$module_name"; then
errors=$((errors + 1))
fi
fi
done
if [ "$errors" -gt 0 ]; then
die "Breaking change check failed. Please revert changes or mark them as compatible."
fi
echo "All OpenAPI Breaking Change checks passed."

View File

@ -0,0 +1,98 @@
#!/usr/bin/env sh
set -eu
# Check OpenAPI contract levels for multi-module layout.
# - For PRs targeting main: require provider contract level >= L2.
# - Always require info.x-contract-level exists and is L0-L3.
#
# Expected locations:
# - spec/<module>/openapi.provider.yaml
# - spec/<module>/openapi.deps.yaml (optional)
require_provider_l2="${REQUIRE_PROVIDER_L2:-0}"
die() {
echo "ERROR: $*" >&2
exit 1
}
level_rank() {
case "$1" in
L0) echo 0;;
L1) echo 1;;
L2) echo 2;;
L3) echo 3;;
*) echo -1;;
esac
}
extract_level() {
# Extracts the first occurrence of info.x-contract-level: L?
# Accepts patterns like:
# x-contract-level: L2
# x-contract-level: "L2"
# under info:
file="$1"
awk '
BEGIN{in_info=0; level=""}
{
# detect "info:" at any indentation
if ($0 ~ /^[[:space:]]*info:[[:space:]]*$/) { in_info=1; info_indent=match($0,/[^ ]/)-1; next }
if (in_info==1) {
# if indentation decreases or new top-level key begins, leave info block
cur_indent=match($0,/[^ ]/)-1;
if (cur_indent <= info_indent && $0 ~ /^[^[:space:]]/ ) { in_info=0 }
}
if (in_info==1 && level=="" && $0 ~ /^[[:space:]]*x-contract-level:[[:space:]]*/) {
line=$0
sub(/^[[:space:]]*x-contract-level:[[:space:]]*/,"",line)
gsub(/"|\047/,"",line)
# strip comments
sub(/[[:space:]]*#.*/,"",line)
gsub(/[[:space:]]+/,"",line)
level=line
}
}
END{print level}
' "$file"
}
check_file_level() {
file="$1"
kind="$2" # provider|deps
[ -f "$file" ] || die "Missing OpenAPI file: $file"
level="$(extract_level "$file" | tr -d '\r')"
[ -n "$level" ] || die "$file: missing info.x-contract-level (expected under info: x-contract-level: L0|L1|L2|L3)"
rank="$(level_rank "$level")"
[ "$rank" -ge 0 ] || die "$file: invalid x-contract-level '$level' (expected L0|L1|L2|L3)"
if [ "$kind" = "provider" ] && [ "$require_provider_l2" = "1" ]; then
if [ "$rank" -lt 2 ]; then
die "$file: provider contract-level must be >= L2 for merge-to-main (current: $level)"
fi
fi
echo "OK: $file level=$level"
}
# Find all provider openapi files under spec/*
provider_files="$(find spec -mindepth 2 -maxdepth 2 -type f -name 'openapi.provider.yaml' 2>/dev/null || true)"
[ -n "$provider_files" ] || die "No provider OpenAPI found. Expected at least one spec/<module>/openapi.provider.yaml"
# Provider files always must have a valid level; for main merges, require >= L2
for f in $provider_files; do
check_file_level "$f" provider
done
# Deps files are optional, but if present must have valid level
for d in $(find spec -mindepth 2 -maxdepth 2 -type f -name 'openapi.deps.yaml' 2>/dev/null || true); do
check_file_level "$d" deps
done
echo "All OpenAPI contract level checks passed."

View File

@ -0,0 +1,55 @@
#!/usr/bin/env sh
set -eu
# Check AC (Acceptance Criteria) Traceability.
# 1. Collect all AC IDs defined in spec/**/requirements.md (format: [AC-FEATURE-NN])
# 2. Collect all AC IDs referenced in src/** and test/** (format: [AC-FEATURE-NN])
# 3. Verify every referenced AC ID exists in requirements.
die() {
echo "ERROR: $*" >&2
exit 1
}
# 1. Collect defined ACs from requirements
defined_acs_file=$(mktemp)
# Matches patterns like [AC-REG-01]
find spec -name "requirements.md" -exec grep -o "\[AC-[A-Z0-9]\+-[0-9]\{2\}\]" {} + | sed 's/.*\[\(AC-[A-Z0-9]\+-[0-9]\{2\}\)\].*/\1/' | sort -u > "$defined_acs_file"
if [ ! -s "$defined_acs_file" ]; then
echo "Warning: No AC IDs found in spec/**/requirements.md. Skipping traceability check."
rm -f "$defined_acs_file"
exit 0
fi
echo "Found $(wc -l < "$defined_acs_file") defined AC IDs in requirements."
# 2. Collect referenced ACs from src/ and test/
referenced_acs_file=$(mktemp)
# Search in src and test directories
find src test -type f \( -name "*.java" -o -name "*.vue" -o -name "*.ts" -o -name "*.tsx" -o -name "*.md" \) -exec grep -o "\[AC-[A-Z0-9]\+-[0-9]\{2\}\]" {} + | sed 's/.*\[\(AC-[A-Z0-9]\+-[0-9]\{2\}\)\].*/\1/' | sort -u > "$referenced_acs_file"
if [ ! -s "$referenced_acs_file" ]; then
echo "OK: No AC references found in code. Traceability check skipped."
rm -f "$defined_acs_file" "$referenced_acs_file"
exit 0
fi
echo "Found $(wc -l < "$referenced_acs_file") AC references in code."
# 3. Verify references
missing_acs=0
while read -r ac; do
if ! grep -q "^$ac$" "$defined_acs_file"; then
echo "ERROR: Referenced AC ID '$ac' not found in any requirements.md"
missing_acs=$((missing_acs + 1))
fi
done < "$referenced_acs_file"
rm -f "$defined_acs_file" "$referenced_acs_file"
if [ "$missing_acs" -gt 0 ]; then
die "Traceability check failed: $missing_acs unknown AC reference(s) found."
fi
echo "OK: All AC references in code are traceable to requirements."

View File

@ -0,0 +1,7 @@
openapi: 3.0.0
info:
title: Test API
version: 1.0.0
x-contract-level: L2
paths: {}