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

@@ -38,26 +38,23 @@ class Gitea {
clientId: process.env.GITEA_CLIENT_ID!,
clientSecret: process.env.GITEA_CLIENT_SECRET!,
redirectUri: process.env.GITEA_REDIRECT_URI!,
}
};
}
async getToken(code: string) {
const { giteaUrl, clientId, clientSecret, redirectUri } = this.config;
console.log('this.config', this.config);
const response = await fetch(
`${giteaUrl}/login/oauth/access_token`,
{
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
}),
},
);
const response = await fetch(`${giteaUrl}/login/oauth/access_token`, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
}),
});
if (!response.ok) {
console.log(await response.json());
throw new Error(`Fetch failed: ${response.status}`);
@@ -108,19 +105,23 @@ class Gitea {
* @param accessToken 访问令牌
* @param sha 分支名称或提交SHA
*/
async getCommits(owner: string, repo: string, accessToken: string, sha?: string) {
const url = new URL(`${this.config.giteaUrl}/api/v1/repos/${owner}/${repo}/commits`);
async getCommits(
owner: string,
repo: string,
accessToken: string,
sha?: string,
) {
const url = new URL(
`${this.config.giteaUrl}/api/v1/repos/${owner}/${repo}/commits`,
);
if (sha) {
url.searchParams.append('sha', sha);
}
const response = await fetch(
url.toString(),
{
method: 'GET',
headers: this.getHeaders(accessToken),
},
);
const response = await fetch(url.toString(), {
method: 'GET',
headers: this.getHeaders(accessToken),
});
if (!response.ok) {
throw new Error(`Fetch failed: ${response.status}`);
}
@@ -133,7 +134,7 @@ class Gitea {
'Content-Type': 'application/json',
};
if (accessToken) {
headers['Authorization'] = `token ${accessToken}`;
headers.Authorization = `token ${accessToken}`;
}
return headers;
}