chore: 统一本地服务器与远程仓库源码
- 合并 main 与 master 历史并以服务器结构为基线 - 保留迁移、数据保留、AWS 账单与部署安全能力 - 建立 SDD 规格和 CI 验证闭环
This commit is contained in:
commit
fd60361d93
460 files changed
+37492
-23871
No files matched your search
+143
-64
@@ -6,8 +6,9 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"ezops/model"
|
||||
"ezops/middleware"
|
||||
"ezops/model"
|
||||
"ezops/pkg/crypto"
|
||||
ezredis "ezops/pkg/redis"
|
||||
"ezops/pkg/toolinstaller"
|
||||
|
||||
@@ -57,11 +58,12 @@ type PipelineHandler struct {
|
||||
db *gorm.DB
|
||||
cache ezredis.Cache
|
||||
toolInstaller *toolinstaller.ToolInstaller
|
||||
crypt *crypto.SecretBox
|
||||
}
|
||||
|
||||
// NewPipelineHandler 创建流水线处理器
|
||||
func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache, ti *toolinstaller.ToolInstaller) *PipelineHandler {
|
||||
h := &PipelineHandler{db: db, cache: cache, toolInstaller: ti}
|
||||
func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache, ti *toolinstaller.ToolInstaller, masterKey string) *PipelineHandler {
|
||||
h := &PipelineHandler{db: db, cache: cache, toolInstaller: ti, crypt: crypto.NewSecretBox(masterKey)}
|
||||
h.ensureBuildMasterConfig()
|
||||
return h
|
||||
}
|
||||
@@ -69,7 +71,7 @@ func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache, ti *toolinstaller.Tool
|
||||
// PipelineListItem 列表项(含最近一次运行摘要)// Logan.Li
|
||||
type PipelineListItem struct {
|
||||
model.Pipeline
|
||||
LastRunStages string `json:"last_run_stages,omitempty"` // JSON: [{name,status}]
|
||||
LastRunStages string `json:"last_run_stages,omitempty"` // JSON: [{name,status}]
|
||||
LastImageTag string `json:"last_image_tag,omitempty"`
|
||||
LastCommitID string `json:"last_commit_id,omitempty"`
|
||||
LastRunDuration int `json:"last_duration,omitempty"`
|
||||
@@ -112,7 +114,11 @@ func (h *PipelineHandler) ListPipelines(c *gin.Context) {
|
||||
db.Count(&total)
|
||||
|
||||
var pipelines []model.Pipeline
|
||||
db.Preload("Environment").Offset(query.GetOffset()).Limit(query.GetLimit()).Order("updated_at DESC").Find(&pipelines)
|
||||
db.Preload("Environment").
|
||||
Offset(query.GetOffset()).
|
||||
Limit(query.GetLimit()).
|
||||
Order("CASE WHEN last_run_at IS NULL THEN 1 ELSE 0 END ASC, last_run_at DESC, updated_at DESC").
|
||||
Find(&pipelines)
|
||||
|
||||
// 批量获取每个流水线最近一次运行的摘要(阶段状态 + 镜像 + 耗时)// Logan.Li
|
||||
items := make([]PipelineListItem, len(pipelines))
|
||||
@@ -123,7 +129,7 @@ func (h *PipelineHandler) ListPipelines(c *gin.Context) {
|
||||
}
|
||||
// 子查询:每个 pipeline_id 的最新 run id
|
||||
var latestRuns []model.PipelineRun
|
||||
h.db.Where("id IN (SELECT MAX(id) FROM ops_pipeline_runs WHERE pipeline_id IN ? AND status IN ('success','failed','running','pending') GROUP BY pipeline_id)", pids).
|
||||
h.db.Where("id IN (SELECT MAX(id) FROM deploy_pipeline_runs WHERE pipeline_id IN ? AND status IN ('success','failed','running','pending') GROUP BY pipeline_id)", pids).
|
||||
Find(&latestRuns)
|
||||
runMap := map[uint]*model.PipelineRun{}
|
||||
for i := range latestRuns {
|
||||
@@ -147,8 +153,8 @@ func (h *PipelineHandler) ListPipelines(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: 200,
|
||||
Data: model.ListResponse{List: items, Total: total},
|
||||
Code: 200,
|
||||
Data: model.ListResponse{List: items, Total: total},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -211,30 +217,29 @@ func (h *PipelineHandler) CreatePipeline(c *gin.Context) {
|
||||
}
|
||||
|
||||
pipeline := model.Pipeline{
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
JobName: req.JobName,
|
||||
Description: req.Description,
|
||||
Type: req.Type,
|
||||
Source: req.Source,
|
||||
Branch: req.Branch,
|
||||
Dockerfile: req.Dockerfile,
|
||||
Stages: req.Stages,
|
||||
Variables: req.Variables,
|
||||
DeployMode: req.DeployMode,
|
||||
DeployTarget: req.DeployTarget,
|
||||
ServerIDs: req.ServerIDs,
|
||||
DeployRemotePath: req.DeployRemotePath,
|
||||
DeployScript: req.DeployScript,
|
||||
K8sClusterID: req.K8sClusterID,
|
||||
K8sNamespace: req.K8sNamespace,
|
||||
K8sDeployment: req.K8sDeployment,
|
||||
K8sContainerName: req.K8sContainerName,
|
||||
RepoID: req.RepoID,
|
||||
RegistryID: req.RegistryID,
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
JobName: req.JobName,
|
||||
Description: req.Description,
|
||||
Type: req.Type,
|
||||
CIProvider: normalizeCIProvider(req.CIProvider),
|
||||
Source: req.Source,
|
||||
Branch: req.Branch,
|
||||
Dockerfile: req.Dockerfile,
|
||||
Stages: req.Stages,
|
||||
Variables: req.Variables,
|
||||
DeployMode: req.DeployMode,
|
||||
DeployTarget: req.DeployTarget,
|
||||
ServerIDs: req.ServerIDs,
|
||||
DeployRemotePath: req.DeployRemotePath,
|
||||
DeployScript: req.DeployScript,
|
||||
K8sClusterID: req.K8sClusterID,
|
||||
K8sNamespace: req.K8sNamespace,
|
||||
K8sDeployment: req.K8sDeployment,
|
||||
K8sContainerName: req.K8sContainerName,
|
||||
GitCredentialID: req.GitCredentialID,
|
||||
RegistryCredentialID: req.RegistryCredentialID,
|
||||
EnvironmentID: req.EnvironmentID,
|
||||
EnvironmentID: req.EnvironmentID,
|
||||
// 触发配置
|
||||
TriggerMode: req.TriggerMode,
|
||||
WatchBranches: req.WatchBranches,
|
||||
@@ -242,11 +247,13 @@ func (h *PipelineHandler) CreatePipeline(c *gin.Context) {
|
||||
CronExpr: req.CronExpr,
|
||||
WebhookToken: req.WebhookToken,
|
||||
// 缓存
|
||||
CachePaths: req.CachePaths,
|
||||
CachePaths: req.CachePaths,
|
||||
JenkinsJobName: req.JenkinsJobName,
|
||||
JenkinsJobURL: req.JenkinsJobURL,
|
||||
// 并发控制
|
||||
MaxExecutors: req.MaxExecutors,
|
||||
BuildNodeID: req.BuildNodeID,
|
||||
Enabled: true,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
if err := h.db.Create(&pipeline).Error; err != nil {
|
||||
@@ -301,38 +308,105 @@ func (h *PipelineHandler) UpdatePipeline(c *gin.Context) {
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
if req.Name != "" { updates["name"] = req.Name }
|
||||
if req.JobName != "" { updates["job_name"] = req.JobName }
|
||||
if req.Description != "" { updates["description"] = req.Description }
|
||||
if req.Type != "" { updates["type"] = req.Type }
|
||||
if req.Source != "" { updates["source"] = req.Source }
|
||||
if req.Branch != "" { updates["branch"] = req.Branch }
|
||||
if req.Dockerfile != "" { updates["dockerfile"] = req.Dockerfile }
|
||||
if req.Stages != "" { updates["stages"] = req.Stages }
|
||||
if req.Variables != "" { updates["variables"] = req.Variables }
|
||||
if req.DeployMode != "" { updates["deploy_mode"] = req.DeployMode }
|
||||
if req.DeployTarget != "" { updates["deploy_target"] = req.DeployTarget }
|
||||
if req.ServerIDs != "" { updates["server_ids"] = req.ServerIDs }
|
||||
if req.DeployRemotePath != "" { updates["deploy_remote_path"] = req.DeployRemotePath }
|
||||
if req.DeployScript != "" { updates["deploy_script"] = req.DeployScript }
|
||||
if req.K8sNamespace != "" { updates["k8s_namespace"] = req.K8sNamespace }
|
||||
if req.K8sDeployment != "" { updates["k8s_deployment"] = req.K8sDeployment }
|
||||
if req.K8sContainerName != "" { updates["k8s_container_name"] = req.K8sContainerName }
|
||||
if req.K8sClusterID != nil { updates["k8s_cluster_id"] = req.K8sClusterID }
|
||||
if req.RepoID != nil { updates["repo_id"] = req.RepoID }
|
||||
if req.RegistryID != nil { updates["registry_id"] = req.RegistryID }
|
||||
if req.GitCredentialID != nil { updates["git_credential_id"] = req.GitCredentialID }
|
||||
if req.RegistryCredentialID != nil { updates["registry_credential_id"] = req.RegistryCredentialID }
|
||||
if req.EnvironmentID != nil { updates["environment_id"] = req.EnvironmentID }
|
||||
if req.TriggerMode != "" { updates["trigger_mode"] = req.TriggerMode }
|
||||
if req.WatchBranches != "" { updates["watch_branches"] = req.WatchBranches }
|
||||
if req.ExcludeBranch != "" { updates["exclude_branch"] = req.ExcludeBranch }
|
||||
if req.CronExpr != "" { updates["cron_expr"] = req.CronExpr }
|
||||
if req.WebhookToken != "" { updates["webhook_token"] = req.WebhookToken }
|
||||
if req.CachePaths != "" { updates["cache_paths"] = req.CachePaths }
|
||||
if req.Enabled != nil { updates["enabled"] = req.Enabled }
|
||||
if req.MaxExecutors > 0 { updates["max_executors"] = req.MaxExecutors }
|
||||
if req.BuildNodeID != nil { updates["build_node_id"] = req.BuildNodeID }
|
||||
if req.Name != "" {
|
||||
updates["name"] = req.Name
|
||||
}
|
||||
if req.JobName != "" {
|
||||
updates["job_name"] = req.JobName
|
||||
}
|
||||
if req.Description != "" {
|
||||
updates["description"] = req.Description
|
||||
}
|
||||
if req.Type != "" {
|
||||
updates["type"] = req.Type
|
||||
}
|
||||
if req.CIProvider != "" {
|
||||
updates["ci_provider"] = normalizeCIProvider(req.CIProvider)
|
||||
}
|
||||
if req.Source != "" {
|
||||
updates["source"] = req.Source
|
||||
}
|
||||
if req.Branch != "" {
|
||||
updates["branch"] = req.Branch
|
||||
}
|
||||
if req.Dockerfile != "" {
|
||||
updates["dockerfile"] = req.Dockerfile
|
||||
}
|
||||
if req.Stages != "" {
|
||||
updates["stages"] = req.Stages
|
||||
}
|
||||
if req.Variables != "" {
|
||||
updates["variables"] = req.Variables
|
||||
}
|
||||
if req.DeployMode != "" {
|
||||
updates["deploy_mode"] = req.DeployMode
|
||||
}
|
||||
if req.DeployTarget != "" {
|
||||
updates["deploy_target"] = req.DeployTarget
|
||||
}
|
||||
if req.ServerIDs != "" {
|
||||
updates["server_ids"] = req.ServerIDs
|
||||
}
|
||||
if req.DeployRemotePath != "" {
|
||||
updates["deploy_remote_path"] = req.DeployRemotePath
|
||||
}
|
||||
if req.DeployScript != "" {
|
||||
updates["deploy_script"] = req.DeployScript
|
||||
}
|
||||
if req.K8sNamespace != "" {
|
||||
updates["k8s_namespace"] = req.K8sNamespace
|
||||
}
|
||||
if req.K8sDeployment != "" {
|
||||
updates["k8s_deployment"] = req.K8sDeployment
|
||||
}
|
||||
if req.K8sContainerName != "" {
|
||||
updates["k8s_container_name"] = req.K8sContainerName
|
||||
}
|
||||
if req.K8sClusterID != nil {
|
||||
updates["k8s_cluster_id"] = req.K8sClusterID
|
||||
}
|
||||
if req.GitCredentialID != nil {
|
||||
updates["git_credential_id"] = req.GitCredentialID
|
||||
}
|
||||
if req.RegistryCredentialID != nil {
|
||||
updates["registry_credential_id"] = req.RegistryCredentialID
|
||||
}
|
||||
if req.EnvironmentID != nil {
|
||||
updates["environment_id"] = req.EnvironmentID
|
||||
}
|
||||
if req.TriggerMode != "" {
|
||||
updates["trigger_mode"] = req.TriggerMode
|
||||
}
|
||||
if req.WatchBranches != "" {
|
||||
updates["watch_branches"] = req.WatchBranches
|
||||
}
|
||||
if req.ExcludeBranch != "" {
|
||||
updates["exclude_branch"] = req.ExcludeBranch
|
||||
}
|
||||
if req.CronExpr != "" {
|
||||
updates["cron_expr"] = req.CronExpr
|
||||
}
|
||||
if req.WebhookToken != "" {
|
||||
updates["webhook_token"] = req.WebhookToken
|
||||
}
|
||||
if req.CachePaths != "" {
|
||||
updates["cache_paths"] = req.CachePaths
|
||||
}
|
||||
if req.JenkinsJobName != "" {
|
||||
updates["jenkins_job_name"] = req.JenkinsJobName
|
||||
}
|
||||
if req.JenkinsJobURL != "" {
|
||||
updates["jenkins_job_url"] = req.JenkinsJobURL
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
updates["enabled"] = req.Enabled
|
||||
}
|
||||
if req.MaxExecutors > 0 {
|
||||
updates["max_executors"] = req.MaxExecutors
|
||||
}
|
||||
if req.BuildNodeID != nil {
|
||||
updates["build_node_id"] = req.BuildNodeID
|
||||
}
|
||||
|
||||
if err := h.db.Model(&pipeline).Updates(updates).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Response{
|
||||
@@ -404,6 +478,11 @@ func (h *PipelineHandler) TriggerPipeline(c *gin.Context) {
|
||||
var req model.TriggerPipelineRequest
|
||||
c.ShouldBindJSON(&req)
|
||||
|
||||
if pipeline.CIProvider == "jenkins" {
|
||||
h.triggerJenkinsPipeline(c, pipeline, req)
|
||||
return
|
||||
}
|
||||
|
||||
var maxBuildNumber int
|
||||
h.db.Model(&model.PipelineRun{}).Where("pipeline_id = ?", id).
|
||||
Select("COALESCE(MAX(build_number), 0)").Scan(&maxBuildNumber)
|
||||
|
||||
Reference in new issue
Block a user