pipeline-app/bin/init_data.py

229 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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))