package handlers import ( "net/http" "strconv" "ezops/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // PipelineHandler 流水线处理器 type PipelineHandler struct { db *gorm.DB } // NewPipelineHandler 创建流水线处理器 func NewPipelineHandler(db *gorm.DB) *PipelineHandler { return &PipelineHandler{db: db} } // ListPipelines 获取流水线列表 // @Summary 获取流水线列表 // @Description 获取所有流水线列表 // @Tags 流水线 // @Produce json // @Security Bearer // @Param page query int false "页码" // @Param page_size query int false "每页数量" // @Success 200 {object} models.Response{data=models.ListResponse} // @Router /pipelines [get] func (h *PipelineHandler) ListPipelines(c *gin.Context) { var query models.PageQuery c.ShouldBindQuery(&query) var total int64 h.db.Model(&models.Pipeline{}).Count(&total) var pipelines []models.Pipeline h.db.Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&pipelines) c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: models.ListResponse{ List: pipelines, Total: total, }, }) } // GetPipeline 获取流水线详情 // @Summary 获取流水线详情 // @Description 获取指定流水线的详细信息 // @Tags 流水线 // @Produce json // @Security Bearer // @Param id path int true "流水线ID" // @Success 200 {object} models.Response{data=models.Pipeline} // @Router /pipelines/{id} [get] func (h *PipelineHandler) GetPipeline(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var pipeline models.Pipeline if err := h.db.First(&pipeline, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "流水线不存在", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: pipeline, }) } // CreatePipeline 创建流水线 // @Summary 创建流水线 // @Description 创建新流水线 // @Tags 流水线 // @Accept json // @Produce json // @Security Bearer // @Param request body models.CreatePipelineRequest true "创建请求" // @Success 200 {object} models.Response{data=models.Pipeline} // @Router /pipelines [post] func (h *PipelineHandler) CreatePipeline(c *gin.Context) { var req models.CreatePipelineRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } pipeline := models.Pipeline{ Name: req.Name, Code: req.Code, Description: req.Description, Type: req.Type, Source: req.Source, Branch: req.Branch, Dockerfile: req.Dockerfile, Stages: req.Stages, Variables: req.Variables, Enabled: true, } if err := h.db.Create(&pipeline).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "创建失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "创建成功", Data: pipeline, }) } // UpdatePipeline 更新流水线 // @Summary 更新流水线 // @Description 更新指定流水线 // @Tags 流水线 // @Accept json // @Produce json // @Security Bearer // @Param id path int true "流水线ID" // @Param request body models.CreatePipelineRequest true "更新请求" // @Success 200 {object} models.Response{data=models.Pipeline} // @Router /pipelines/{id} [put] func (h *PipelineHandler) UpdatePipeline(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var req models.CreatePipelineRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } var pipeline models.Pipeline if err := h.db.First(&pipeline, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "流水线不存在", }) return } updates := map[string]interface{}{ "name": req.Name, "description": req.Description, "type": req.Type, "source": req.Source, "branch": req.Branch, "dockerfile": req.Dockerfile, "stages": req.Stages, "variables": req.Variables, } if err := h.db.Model(&pipeline).Updates(updates).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "更新失败", }) return } h.db.First(&pipeline, id) c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "更新成功", Data: pipeline, }) } // DeletePipeline 删除流水线 // @Summary 删除流水线 // @Description 删除指定流水线 // @Tags 流水线 // @Produce json // @Security Bearer // @Param id path int true "流水线ID" // @Success 200 {object} models.Response // @Router /pipelines/{id} [delete] func (h *PipelineHandler) DeletePipeline(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) if err := h.db.Delete(&models.Pipeline{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "删除失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "删除成功", }) } // TriggerPipeline 触发流水线 // @Summary 触发流水线 // @Description 手动触发流水线执行 // @Tags 流水线 // @Accept json // @Produce json // @Security Bearer // @Param id path int true "流水线ID" // @Param request body models.TriggerPipelineRequest true "触发请求" // @Success 200 {object} models.Response{data=models.PipelineRun} // @Router /pipelines/{id}/trigger [post] func (h *PipelineHandler) TriggerPipeline(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var pipeline models.Pipeline if err := h.db.First(&pipeline, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "流水线不存在", }) return } var req models.TriggerPipelineRequest c.ShouldBindJSON(&req) // 获取最新构建号 var maxBuildNumber int h.db.Model(&models.PipelineRun{}).Where("pipeline_id = ?", id).Select("COALESCE(MAX(build_number), 0)").Scan(&maxBuildNumber) run := models.PipelineRun{ PipelineID: uint(id), BuildNumber: maxBuildNumber + 1, Status: "pending", Branch: req.Branch, TriggeredBy: "manual", } if req.Branch == "" { run.Branch = pipeline.Branch } if err := h.db.Create(&run).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "触发失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "触发成功", Data: run, }) } // ListRuns 获取运行记录列表 // @Summary 获取运行记录列表 // @Description 获取指定流水线的运行记录 // @Tags 流水线 // @Produce json // @Security Bearer // @Param id path int true "流水线ID" // @Param page query int false "页码" // @Param page_size query int false "每页数量" // @Success 200 {object} models.Response{data=models.ListResponse} // @Router /pipelines/{id}/runs [get] func (h *PipelineHandler) ListRuns(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var query models.PageQuery c.ShouldBindQuery(&query) db := h.db.Model(&models.PipelineRun{}).Where("pipeline_id = ?", id) var total int64 db.Count(&total) var runs []models.PipelineRun db.Order("created_at DESC"). Offset(query.GetOffset()). Limit(query.GetLimit()). Find(&runs) c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: models.ListResponse{ List: runs, Total: total, }, }) } // ListReleases 获取发布列表 // @Summary 获取发布列表 // @Description 获取所有应用发布列表 // @Tags 应用发布 // @Produce json // @Security Bearer // @Param page query int false "页码" // @Param page_size query int false "每页数量" // @Success 200 {object} models.Response{data=models.ListResponse} // @Router /releases [get] func (h *PipelineHandler) ListReleases(c *gin.Context) { var query models.PageQuery c.ShouldBindQuery(&query) var total int64 h.db.Model(&models.AppRelease{}).Count(&total) var releases []models.AppRelease h.db.Order("created_at DESC"). Offset(query.GetOffset()). Limit(query.GetLimit()). Find(&releases) c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "success", Data: models.ListResponse{ List: releases, Total: total, }, }) } // CreateRelease 创建发布 // @Summary 创建发布 // @Description 创建新应用发布 // @Tags 应用发布 // @Accept json // @Produce json // @Security Bearer // @Param request body models.CreateAppReleaseRequest true "创建请求" // @Success 200 {object} models.Response{data=models.AppRelease} // @Router /releases [post] func (h *PipelineHandler) CreateRelease(c *gin.Context) { var req models.CreateAppReleaseRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } release := models.AppRelease{ AppName: req.AppName, Version: req.Version, Environment: req.Environment, Status: "pending", CommitID: req.CommitID, CommitMsg: req.CommitMsg, Servers: "[]", Description: req.Description, } if err := h.db.Create(&release).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "创建失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "创建成功", Data: release, }) } // ApproveRelease 审批发布 // @Summary 审批发布 // @Description 审批应用发布 // @Tags 应用发布 // @Produce json // @Security Bearer // @Param id path int true "发布ID" // @Success 200 {object} models.Response{data=models.AppRelease} // @Router /releases/{id}/approve [post] func (h *PipelineHandler) ApproveRelease(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var release models.AppRelease if err := h.db.First(&release, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "发布不存在", }) return } release.Status = "approved" // release.Approver = middleware.GetUsername(c) // now := time.Now() // release.ApprovedAt = &now if err := h.db.Save(&release).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "审批失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "审批成功", Data: release, }) } // DeployRelease 部署发布 // @Summary 部署发布 // @Description 部署应用发布 // @Tags 应用发布 // @Produce json // @Security Bearer // @Param id path int true "发布ID" // @Success 200 {object} models.Response{data=models.AppRelease} // @Router /releases/{id}/deploy [post] func (h *PipelineHandler) DeployRelease(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var release models.AppRelease if err := h.db.First(&release, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "发布不存在", }) return } release.Status = "deploying" if err := h.db.Save(&release).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "部署失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "部署中", Data: release, }) } // RollbackRelease 回滚发布 // @Summary 回滚发布 // @Description 回滚应用发布 // @Tags 应用发布 // @Produce json // @Security Bearer // @Param id path int true "发布ID" // @Success 200 {object} models.Response{data=models.AppRelease} // @Router /releases/{id}/rollback [post] func (h *PipelineHandler) RollbackRelease(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var release models.AppRelease if err := h.db.First(&release, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{ Code: 404, Message: "发布不存在", }) return } release.Status = "rolled_back" // now := time.Now() // release.RollbackAt = &now if err := h.db.Save(&release).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{ Code: 500, Message: "回滚失败", }) return } c.JSON(http.StatusOK, models.Response{ Code: 200, Message: "回滚成功", Data: release, }) }