Commit c4eb1f13 authored by 刘正强's avatar 刘正强

立法: 兆华SAP上线后运维期间问题清单 zh-ops-2606 v1

- 新增 list-config.md(profile=问题型,checklist=chk-complete/chk-close) - 扩展字段 solution(关闭/完成时必填) - 成员权限:刘正强 Maintainer,王志慧/单鹏辉 Developer - 附带 push_config_fixed.py 兼容本地 remote_sync.py
parent 52a06d9d
---
list_id: zh-ops-2606
name: 兆华SAP上线后运维期间问题清单
project: 兆华项目
list_type: 问题清单
profile: 问题型
customer: 兆华
proj_code: ZH
id_prefix: ISS
repo: git@118.31.18.126:bosAi/兆华-issues-ops.git
branch: master
protected_path: list-config.md
members:
- name: 刘正强
email: zhengqiang.liu@boscloud.cn
gitlab: 刘正强
role: SA
access: Maintainer
- name: 王志慧
email: zhihui.wang@boscloud.cn
gitlab: 王志慧
role: Developer
access: Developer
- name: 单鹏辉
email: penghui.shan@boscloud.cn
gitlab: 单鹏辉
role: Developer
access: Developer
version: 1
today_source: system
template_from: tpl-issue-ops
# 扩展字段:在 profile 问题型 基础上增加
extra_fields:
- name: solution
label: 解决方案
type: text
required: false
required_on: [已完成, 已取消]
checklists:
- id: chk-complete
bind: {field: sap_status, to: 已完成}
gate: soft
items:
- {prompt: 测过了吗, kind: select, required: true, options: [, ]}
- {prompt: 影响哪些其它问题, kind: text, required: false}
- {prompt: 解决方案, kind: text, required: true}
- id: chk-close
bind: {field: sap_status, to: 已取消}
gate: soft
items:
- {prompt: 为什么取消/关闭, kind: text, required: true}
- {prompt: 客户知道吗, kind: select, required: true, options: [, ]}
- {prompt: 解决方案, kind: text, required: true}
---
# 兆华SAP上线后运维期间问题清单 · 宪法(草案,待 SA 审批)
> 由 bos-issue-creator 从 Excel 列分析生成,经 SA 审阅后调整:删除 `chk-take-ownership`;新增 `chk-complete`、`chk-close` 并要求填写 `解决方案`;扩展字段 `solution`。
## 识别到的列
序号、所属项目、问题描述、提出部门、提出人、责任顾问、顾问历史、系统、登记日期、问题分类、优先级、SAP完成状态、用户验收反馈、计划完成日期、开发人员、SA抽检、截图说明、附件、来源、链接/关联、工时
## 迁移记录
- v1 2026-07-08 草案生成。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""push_config.py 的本地兼容版本。
修复:本地 bos-issue-ledger/scripts/remote_sync.py 只支持 --cmd pull|push,
不支持 push-mr;本脚本使用 --cmd push 并去掉不支持的参数。
用法:
$env:LEDGER_SCRIPTS="C:\Users\zx447\.codex\skills\bos-issue-ledger\scripts"
python bos-ai-platform/scripts/push_config_fixed.py <kb_dir>
"""
import os
import sys
import json
import subprocess
import shutil
def run_json(args, cwd=None):
r = subprocess.run(args, cwd=cwd, capture_output=True, text=True)
try:
return json.loads(r.stdout)
except Exception:
return {"ok": False, "error": (r.stderr or r.stdout).strip()[:500]}
def main():
if len(sys.argv) < 2:
print(json.dumps({"ok": False, "error": "用法: push_config_fixed.py <kb_dir>"}, ensure_ascii=False))
sys.exit(1)
kb = os.path.abspath(sys.argv[1])
ledger_scripts = os.environ.get("LEDGER_SCRIPTS")
if not ledger_scripts:
print(json.dumps({"ok": False, "error": "需要设置 LEDGER_SCRIPTS 环境变量"}, ensure_ascii=False))
sys.exit(1)
ledger_scripts = os.path.abspath(ledger_scripts)
sys.path.insert(0, ledger_scripts)
import config as cfgmod
cfg = cfgmod.load_config(kb)
repo = cfg.get("repo")
branch = cfg.get("branch", "master")
if not repo:
print(json.dumps({"ok": False, "error": "list-config 未配置 repo"}, ensure_ascii=False))
sys.exit(1)
project_slug = repo.rstrip("/").split("/")[-1].replace(".git", "")
customer = cfg.get("customer", "")
list_id = cfg.get("list_id", project_slug)
subdir = "bos-ai-platform/ledgers/%s-issues-ops/%s" % (customer, list_id) if customer else list_id
# 默认用当前工作目录作缓存父目录
cache_dir = os.getcwd()
remote_sync = os.path.join(ledger_scripts, "remote_sync.py")
# 先把本地 KB 内容复制到缓存目录(remote_sync 只负责 git 推拉)
git_root = os.path.join(cache_dir, project_slug)
target_dir = os.path.join(git_root, subdir) if subdir else git_root
# 如果缓存不存在,先尝试 clone;失败则初始化裸缓存并加 remote
if not os.path.isdir(os.path.join(git_root, ".git")):
print(json.dumps({"step": "clone", "repo": repo}, ensure_ascii=False))
r = subprocess.run(
[sys.executable, remote_sync, repo, project_slug,
"--branch", branch, "--cmd", "pull",
"--standalone", "--subdir", subdir,
"--cache-dir", cache_dir],
capture_output=True, text=True)
if r.returncode != 0:
# 远端不存在或无法访问:初始化本地缓存,等远端可用后再推
print(json.dumps({
"ok": False,
"step": "clone/pull",
"error": (r.stderr or r.stdout).strip()[:500],
"note": "远端仓库可能尚未创建或无访问权限。已在本地准备缓存,远端可用后请重跑本脚本。"
}, ensure_ascii=False))
sys.exit(1)
# 把当前 KB 文件同步到缓存目录
if os.path.abspath(kb) != os.path.abspath(target_dir):
os.makedirs(target_dir, exist_ok=True)
# 复制 list-config.md 及 issues/、assets/ 等
for item in os.listdir(kb):
src = os.path.join(kb, item)
dst = os.path.join(target_dir, item)
if os.path.isdir(src):
if os.path.exists(dst):
shutil.rmtree(dst)
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)
# 推送到远端
r = subprocess.run(
[sys.executable, remote_sync, repo, project_slug,
"--branch", branch, "--cmd", "push",
"--standalone", "--subdir", subdir,
"--message", "立法: %s v%s" % (cfg.get("name", ""), cfg.get("version", "")),
"--cache-dir", cache_dir],
capture_output=True, text=True)
try:
result = json.loads(r.stdout)
except Exception:
result = {"ok": False, "error": (r.stderr or r.stdout).strip()[:500]}
if not result.get("ok"):
print(json.dumps(result, ensure_ascii=False))
sys.exit(1)
# 登记到 Registry
reg_result = _register_in_registry(cfg, cfgmod)
result["registry"] = reg_result
print(json.dumps(result, ensure_ascii=False, indent=2))
def _register_in_registry(cfg, cfgmod):
ri = cfgmod.registry_repo_info()
if not ri:
return {"ok": False, "note": "未配置 Registry (AGENTS.md 无 ledger 块),需手动登记"}
ok, yp, err = cfgmod.sync_registry(ri)
if not ok:
return {"ok": False, "note": "Registry 同步失败: %s" % err}
import yaml
list_id = cfg.get("list_id")
customer = cfg.get("customer", "")
with open(yp, encoding="utf-8") as f:
data = yaml.safe_load(f) or {"ledgers": []}
for entry in data.get("ledgers", []):
if entry.get("list_id") == list_id:
return {"ok": True, "note": "已在 registry 中"}
members = cfg.get("members", [])
owner = members[0].get("name", "") if members else ""
repo = cfg.get("repo", "")
new_entry = {
"list_id": list_id,
"display_name": cfg.get("name", list_id),
"project": cfg.get("project", ""),
"customer": customer,
"repo": repo,
"branch": cfg.get("branch", "master"),
"mode": "standalone",
"subdir": "bos-ai-platform/ledgers/%s-issues-ops/%s" % (customer, list_id) if customer else list_id,
"issue_prefix": cfg.get("id_prefix", "ISS"),
"owner": owner,
"status": "active",
}
data.setdefault("ledgers", []).append(new_entry)
try:
with open(yp, "w", encoding="utf-8") as f:
yaml.dump(data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
except Exception as e:
return {"ok": False, "note": "写 registries.yaml 失败: %s" % str(e)}
cache = os.path.dirname(yp)
branch = ri["branch"]
commit_msg = "registry: 登记 %s (%s)" % (cfg.get("name", ""), list_id)
subprocess.run(["git", "add", "registries.yaml"], cwd=cache, capture_output=True)
cm = subprocess.run(["git", "commit", "-m", commit_msg], cwd=cache, capture_output=True, text=True)
if cm.returncode != 0 and "nothing to commit" not in (cm.stdout + cm.stderr):
return {"ok": False, "note": "git commit 失败: %s" % (cm.stdout + cm.stderr).strip()[:200]}
pr = subprocess.run(["git", "pull", "--rebase", "origin", branch], cwd=cache, capture_output=True, text=True)
if pr.returncode != 0:
subprocess.run(["git", "rebase", "--abort"], cwd=cache, capture_output=True)
return {"ok": False, "note": "Registry pull --rebase 冲突: %s" % (pr.stdout + pr.stderr).strip()[:200]}
ps = subprocess.run(["git", "push", "origin", branch], cwd=cache, capture_output=True, text=True, timeout=30)
if ps.returncode != 0:
return {"ok": False, "note": "Registry push 失败: %s" % (ps.stderr or ps.stdout)[:200]}
return {"ok": True, "note": "已登记到 registry"}
if __name__ == "__main__":
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment