229 lines
9.7 KiB
Python
229 lines
9.7 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Import initialization data for pipeline-app.
|
||
Creates default step types, pipeline templates, and demo data.
|
||
Run: source py3/bin/activate && python bin/init_data.py [--demo]
|
||
"""
|
||
import sys, os, asyncio, json
|
||
|
||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
ROOT_DIR = os.path.dirname(SCRIPT_DIR)
|
||
sys.path.insert(0, os.path.join(ROOT_DIR, 'py3', 'lib', 'python3.10', 'site-packages'))
|
||
sys.path.insert(0, ROOT_DIR)
|
||
|
||
from sqlor.dbpools import DBPools
|
||
from appPublic.jsonConfig import getConfig
|
||
from appPublic.folderUtils import ProgramPath
|
||
from appPublic.uniqueID import getID
|
||
from ahserver.serverenv import ServerEnv
|
||
from ahserver.globalEnv import initEnv
|
||
from appPublic.timeUtils import curDateString, timestampstr
|
||
|
||
# ---- Default step types ----
|
||
STEP_TYPES = [
|
||
# (step_type, display_name, category, is_interactive, description, form_schema)
|
||
('ai_generate', 'AI代码生成', 'AI生成', '0', '由AI自动生成代码', '{}'),
|
||
('ai_review', 'AI代码审查', 'AI审查', '0', '由AI自动审查代码质量', '{}'),
|
||
('ai_test', 'AI测试生成', 'AI测试', '0', '由AI生成测试用例', '{}'),
|
||
('human_review', '人工代码审查', '人工审核', '1', '人工审查代码变更',
|
||
json.dumps({"fields":[{"name":"approved","label":"审批通过","uitype":"switch"},{"name":"comment","label":"审批意见","uitype":"text"}]})),
|
||
('human_approval', '发布审批', '人工审批', '1', '人工审批发布请求',
|
||
json.dumps({"fields":[{"name":"approved","label":"批准发布","uitype":"switch"},{"name":"version","label":"发布版本","uitype":"text"}]})),
|
||
('deploy_staging', '部署到测试环境', '部署', '0', '自动部署到测试环境', '{}'),
|
||
('deploy_production', '部署到生产环境', '部署', '1', '审批后部署到生产环境',
|
||
json.dumps({"fields":[{"name":"confirm","label":"确认部署","uitype":"switch"}]})),
|
||
('run_tests', '运行测试套件', '测试', '0', '自动运行测试套件', '{}'),
|
||
('build_artifact', '构建制品', '构建', '0', '构建发布制品', '{}'),
|
||
('notify_webhook', 'Webhook通知', '通知', '0', '发送Webhook通知', '{}'),
|
||
]
|
||
|
||
# ---- Default pipeline (SDLC template) ----
|
||
SDLC_PIPELINE = {
|
||
'id': 'pipeline_sdlc_default',
|
||
'name': '标准SDLC产线',
|
||
'description': '软件开发生命周期标准流程:AI生成→审查→测试→部署',
|
||
'pipeline_type': 'sdlc',
|
||
'status': 'published',
|
||
'version': '1.0',
|
||
}
|
||
|
||
SDLC_STEPS = [
|
||
('ai_generate', 'AI代码生成', 1),
|
||
('ai_review', 'AI代码审查', 2),
|
||
('run_tests', '自动测试', 3),
|
||
('human_review', '人工代码审查', 4),
|
||
('build_artifact', '构建制品', 5),
|
||
('human_approval', '发布审批', 6),
|
||
('deploy_production', '生产部署', 7),
|
||
]
|
||
|
||
|
||
# ---- 团队沟通(通用问题冒泡):sdlc_general 产线的团队角色 + 问题类型 ----
|
||
TEAM_ROLE_TYPE_CODES = [
|
||
# (k, v)
|
||
('agent', 'Agent'),
|
||
('human', '人'),
|
||
]
|
||
|
||
SDLC_TEAM_ROLES = [
|
||
# (role_name, agentid, role_type, display_name, description)
|
||
('main_agent', '', 'agent', '主Agent', '用户面对话agent,回答问题、路由到客户'),
|
||
('pm', '', 'agent', '项目经理', '审核交付件、退回意见'),
|
||
('requirement', '', 'agent', '需求分析师', '产出需求规格文档'),
|
||
('design', '', 'agent', '系统设计师', '产出架构/DB/API设计'),
|
||
('develop', '', 'agent', '开发工程师', '产出可运行源码'),
|
||
('test', '', 'agent', '测试工程师', '产出测试用例+报告'),
|
||
('deploy', '', 'agent', '部署运维', '产出部署文档+配置'),
|
||
('customer', '', 'human', '客户', '人类客户,最终兜底'),
|
||
]
|
||
|
||
SDLC_PROBLEM_TYPES = [
|
||
# (name, title, description, escalation_path)
|
||
('need_info', '缺信息提问', '角色agent缺关键信息向上提问',
|
||
'["main_agent", "customer"]'),
|
||
('review_reject', '审核退回', 'PM审核退回意见,被退角色响应后复审',
|
||
'["pm"]'),
|
||
('fault_report', '故障报告', '任务失败报障,人工介入',
|
||
'["main_agent", "customer"]'),
|
||
]
|
||
|
||
|
||
async def init_data(demo=False):
|
||
# getConfig 接收应用根目录(内部拼接 conf/config.json),非 config 文件路径
|
||
config = getConfig(ROOT_DIR, NS={'workdir': ROOT_DIR, 'ProgramPath': ProgramPath()})
|
||
DBPools(config.databases)
|
||
initEnv()
|
||
env = ServerEnv()
|
||
env.get_module_dbname = lambda m: 'pipeline' if 'pipeline' in m else 'sage'
|
||
|
||
async with DBPools().sqlorContext('pipeline') as sor:
|
||
# 1. Create step types
|
||
print('Step types:')
|
||
for stype, display, cat, interactive, desc, schema in STEP_TYPES:
|
||
existing = await sor.sqlExe(
|
||
"SELECT step_type FROM pipeline_step_types WHERE step_type=${st}$", {'st': stype})
|
||
if existing:
|
||
print(f' SKIP {stype} ({display})')
|
||
continue
|
||
await sor.C('pipeline_step_types', {
|
||
'step_type': stype, 'display_name': display,
|
||
'category': cat, 'is_interactive': interactive,
|
||
'description': desc, 'form_schema': schema,
|
||
'created_at': timestampstr()
|
||
})
|
||
print(f' ADD {stype} ({display})')
|
||
|
||
# 2. Create default SDLC pipeline
|
||
print('\nPipeline:')
|
||
existing = await sor.sqlExe(
|
||
"SELECT id FROM pipelines WHERE id=${pid}$", {'pid': SDLC_PIPELINE['id']})
|
||
if not existing:
|
||
await sor.C('pipelines', {
|
||
**SDLC_PIPELINE,
|
||
'created_by': 'system',
|
||
'created_at': timestampstr(),
|
||
'updated_at': timestampstr()
|
||
})
|
||
print(f' ADD {SDLC_PIPELINE["name"]}')
|
||
|
||
# Create steps
|
||
for stype, sname, order in SDLC_STEPS:
|
||
await sor.C('pipeline_steps', {
|
||
'id': getID(),
|
||
'pipeline_id': SDLC_PIPELINE['id'],
|
||
'step_order': order,
|
||
'step_name': sname,
|
||
'step_type': stype,
|
||
'step_config': '{}',
|
||
'timeout_seconds': 3600,
|
||
'retry_count': 1,
|
||
'created_at': timestampstr()
|
||
})
|
||
print(f' step {order}: {sname}')
|
||
else:
|
||
print(f' SKIP {SDLC_PIPELINE["name"]} (exists)')
|
||
|
||
# 3. 团队沟通:角色类型代码表 + sdlc_general 团队角色 + 问题类型
|
||
print('\nTeam communication:')
|
||
for k, v in TEAM_ROLE_TYPE_CODES:
|
||
existing = await sor.sqlExe(
|
||
"SELECT id FROM appcodes_kv WHERE parentid='team_role_type' AND k=${k}$", {'k': k})
|
||
if not existing:
|
||
await sor.C('appcodes_kv', {'id': getID(), 'parentid': 'team_role_type', 'k': k, 'v': v})
|
||
print(f' ADD code team_role_type.{k}')
|
||
|
||
# 确保 sdlc_general 产线存在(能力包注册的产线 id)
|
||
existing = await sor.sqlExe("SELECT id FROM pipelines WHERE id='sdlc_general'", {})
|
||
if not existing:
|
||
await sor.C('pipelines', {
|
||
'id': 'sdlc_general', 'name': '通用软件开发产线',
|
||
'description': 'SDLC 开发产线(能力包注册)',
|
||
'pipeline_type': 'dev', 'status': 'published', 'version': '1.0',
|
||
'org_id': '0', 'created_by': 'system',
|
||
'created_at': timestampstr(), 'updated_at': timestampstr(),
|
||
})
|
||
print(' ADD pipeline sdlc_general')
|
||
|
||
for rname, aid, rtype, dname, desc in SDLC_TEAM_ROLES:
|
||
existing = await sor.sqlExe(
|
||
"SELECT id FROM pipeline_team_roles WHERE pipeline_id='sdlc_general' AND role_name=${r}$",
|
||
{'r': rname})
|
||
if existing:
|
||
continue
|
||
await sor.C('pipeline_team_roles', {
|
||
'id': getID(), 'pipeline_id': 'sdlc_general',
|
||
'role_name': rname, 'agentid': aid, 'role_type': rtype,
|
||
'display_name': dname, 'description': desc,
|
||
'created_at': timestampstr(),
|
||
})
|
||
print(f' ADD role {rname}')
|
||
|
||
for pname, ptitle, pdesc, ppath in SDLC_PROBLEM_TYPES:
|
||
existing = await sor.sqlExe(
|
||
"SELECT id FROM pipeline_problem_types WHERE pipeline_id='sdlc_general' AND name=${n}$",
|
||
{'n': pname})
|
||
if existing:
|
||
continue
|
||
await sor.C('pipeline_problem_types', {
|
||
'id': getID(), 'pipeline_id': 'sdlc_general',
|
||
'name': pname, 'title': ptitle, 'description': pdesc,
|
||
'escalation_path': ppath, 'created_at': timestampstr(),
|
||
})
|
||
print(f' ADD problem_type {pname}')
|
||
|
||
# 4. Demo data
|
||
if demo:
|
||
print('\nDemo data:')
|
||
await _create_demo(sor)
|
||
|
||
print('\nInitialization complete.')
|
||
|
||
|
||
async def _create_demo(sor):
|
||
"""Create demo project and iteration."""
|
||
pid = getID()
|
||
existing = await sor.sqlExe("SELECT id FROM sd_projects LIMIT 1", {})
|
||
if existing:
|
||
print(' SKIP (data exists)')
|
||
return
|
||
await sor.C('sd_projects', {
|
||
'id': pid, 'name': 'Pipeline App Demo',
|
||
'description': '产线平台演示项目',
|
||
'project_type': 'web', 'status': 'active',
|
||
'created_by': 'system', 'created_at': timestampstr()
|
||
})
|
||
print(f' ADD project: Pipeline App Demo')
|
||
|
||
iid = getID()
|
||
await sor.C('sd_iterations', {
|
||
'id': iid, 'name': 'Sprint 1 - 基础框架',
|
||
'project_id': pid, 'status': 'in_progress',
|
||
'start_date': curDateString(), 'created_at': timestampstr()
|
||
})
|
||
print(f' ADD iteration: Sprint 1')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
demo_mode = '--demo' in sys.argv
|
||
asyncio.run(init_data(demo=demo_mode))
|