feat: 实现环境变量预设功能 & 移除稀疏检出

## 后端改动
- 添加 Project.envPresets 字段(JSON 格式)
- 移除 Deployment.env 字段,统一使用 envVars
- 更新部署 DTO,支持 envVars (Record<string, string>)
- pipeline-runner 支持解析并注入 envVars 到环境
- 移除稀疏检出模板和相关环境变量
- 优化代码格式(Biome lint & format)

## 前端改动
- 新增 EnvPresetsEditor 组件(支持单选/多选/输入框类型)
- 项目创建/编辑界面集成环境预设编辑器
- 部署界面基于预设动态生成环境变量表单
- 移除稀疏检出表单项
- 项目详情页添加环境变量预设配置 tab
- 优化部署界面布局(基本参数 & 环境变量分区)

## 文档
- 添加完整文档目录结构(docs/)
- 创建设计文档 design-0005(部署流程重构)
- 添加 API 文档、架构设计文档等

## 数据库
- 执行 prisma db push 同步 schema 变更
This commit is contained in:
2026-01-03 22:59:20 +08:00
parent c40532c757
commit d22fdc9618
71 changed files with 9611 additions and 5849 deletions

View File

@@ -17,11 +17,6 @@ export const DEFAULT_PIPELINE_TEMPLATES: PipelineTemplate[] = [
name: 'Git Clone Pipeline',
description: '默认的Git克隆流水线用于从仓库克隆代码',
steps: [
{
name: 'Clone Repository',
order: 0,
script: '# 克隆指定commit的代码\ngit init\ngit remote add origin $REPOSITORY_URL\ngit fetch --depth 1 origin $COMMIT_HASH\ngit checkout -q FETCH_HEAD\n\n# 显示当前提交信息\ngit log --oneline -1',
},
{
name: 'Install Dependencies',
order: 1,
@@ -36,51 +31,21 @@ export const DEFAULT_PIPELINE_TEMPLATES: PipelineTemplate[] = [
name: 'Build Project',
order: 3,
script: '# 构建项目\nnpm run build',
}
]
},
{
name: 'Sparse Checkout Pipeline',
description: '稀疏检出流水线适用于monorepo项目只获取指定目录的代码',
steps: [
{
name: 'Sparse Checkout Repository',
order: 0,
script: '# 进行稀疏检出指定目录的代码\ngit init\ngit remote add origin $REPOSITORY_URL\ngit config core.sparseCheckout true\necho "$SPARSE_CHECKOUT_PATHS" > .git/info/sparse-checkout\ngit fetch --depth 1 origin $COMMIT_HASH\ngit checkout -q FETCH_HEAD\n\n# 显示当前提交信息\ngit log --oneline -1',
},
{
name: 'Install Dependencies',
order: 1,
script: '# 安装项目依赖\nnpm install',
},
{
name: 'Run Tests',
order: 2,
script: '# 运行测试\nnpm test',
},
{
name: 'Build Project',
order: 3,
script: '# 构建项目\nnpm run build',
}
]
],
},
{
name: 'Simple Deploy Pipeline',
description: '简单的部署流水线,包含基本的构建和部署步骤',
steps: [
{
name: 'Clone Repository',
order: 0,
script: '# 克隆指定commit的代码\ngit init\ngit remote add origin $REPOSITORY_URL\ngit fetch --depth 1 origin $COMMIT_HASH\ngit checkout -q FETCH_HEAD',
},
{
name: 'Build and Deploy',
order: 1,
script: '# 构建并部署项目\nnpm run build\n\n# 部署到目标服务器\n# 这里可以添加具体的部署命令',
}
]
}
script:
'# 构建并部署项目\nnpm run build\n\n# 部署到目标服务器\n# 这里可以添加具体的部署命令',
},
],
},
];
/**
@@ -94,10 +59,10 @@ export async function initializePipelineTemplates(): Promise<void> {
const existingTemplates = await prisma.pipeline.findMany({
where: {
name: {
in: DEFAULT_PIPELINE_TEMPLATES.map(template => template.name)
in: DEFAULT_PIPELINE_TEMPLATES.map((template) => template.name),
},
valid: 1
}
valid: 1,
},
});
// 如果没有现有的模板,则创建默认模板
@@ -113,8 +78,8 @@ export async function initializePipelineTemplates(): Promise<void> {
createdBy: 'system',
updatedBy: 'system',
valid: 1,
projectId: null // 模板不属于任何特定项目
}
projectId: null, // 模板不属于任何特定项目
},
});
// 创建模板步骤
@@ -127,8 +92,8 @@ export async function initializePipelineTemplates(): Promise<void> {
pipelineId: pipeline.id,
createdBy: 'system',
updatedBy: 'system',
valid: 1
}
valid: 1,
},
});
}
@@ -148,25 +113,27 @@ export async function initializePipelineTemplates(): Promise<void> {
/**
* 获取所有可用的流水线模板
*/
export async function getAvailableTemplates(): Promise<Array<{id: number, name: string, description: string}>> {
export async function getAvailableTemplates(): Promise<
Array<{ id: number; name: string; description: string }>
> {
try {
const templates = await prisma.pipeline.findMany({
where: {
projectId: null, // 模板流水线没有关联的项目
valid: 1
valid: 1,
},
select: {
id: true,
name: true,
description: true
}
description: true,
},
});
// 处理可能为null的description字段
return templates.map(template => ({
return templates.map((template) => ({
id: template.id,
name: template.name,
description: template.description || ''
description: template.description || '',
}));
} catch (error) {
console.error('Failed to get pipeline templates:', error);
@@ -185,7 +152,7 @@ export async function createPipelineFromTemplate(
templateId: number,
projectId: number,
pipelineName: string,
pipelineDescription: string
pipelineDescription: string,
): Promise<number> {
try {
// 获取模板流水线及其步骤
@@ -193,18 +160,18 @@ export async function createPipelineFromTemplate(
where: {
id: templateId,
projectId: null, // 确保是模板流水线
valid: 1
valid: 1,
},
include: {
steps: {
where: {
valid: 1
valid: 1,
},
orderBy: {
order: 'asc'
}
}
}
order: 'asc',
},
},
},
});
if (!templatePipeline) {
@@ -219,8 +186,8 @@ export async function createPipelineFromTemplate(
projectId: projectId,
createdBy: 'system',
updatedBy: 'system',
valid: 1
}
valid: 1,
},
});
// 复制模板步骤到新流水线
@@ -233,12 +200,14 @@ export async function createPipelineFromTemplate(
pipelineId: newPipeline.id,
createdBy: 'system',
updatedBy: 'system',
valid: 1
}
valid: 1,
},
});
}
console.log(`Created pipeline from template ${templateId}: ${newPipeline.name}`);
console.log(
`Created pipeline from template ${templateId}: ${newPipeline.name}`,
);
return newPipeline.id;
} catch (error) {
console.error('Failed to create pipeline from template:', error);