三方仓库如何实现Zadig流水线自动触发_播报
2023-05-09 11:28:02 来源:运维开发故事

最近因为公司的产研调整,决定将代码仓库从本地的 Gitlab 迁移到云效的 Codeup,不是 Gitlab 不够好,而是 Codeup 在度量、安全等方面比原生的 Gitlab 要好,再则公司的产研管理也迁移到了云效,也为了统一化管理。


(资料图片仅供参考)

有同学可能会问,都用云效了,为什么不直接用它的 AppStack,还要用 Zadig?

AppStack 还处于发展阶段,还有以下问题不适合我们现阶段的需求:

AppStack 不支持管理私有云 Kubernetes 集群(没有公网入口)。AppStack 不支持 Helm 类应用,改造工作比较大。

再则,我也是 Zadig 开源产品的忠实粉丝~~!

但是,Zadig 对非标准的代码仓库的支持力度有限,比如:

非标准代码仓库不支持列出仓库列表,需要自己手动填写非标准代码仓库创建的流水线原生不支持 Webhook 触发

经过综合考虑,手动填写代码仓库信息以及不支持 Webhook 并不影响整体的使用,只是会影响部分项目的工作效率。

但是,为了最小程度上影响原有的产研节奏,我还是准备自己实现三方仓库的 Webhook 触发 Zadig 流水线。因为本身也不复杂。

整体思路

实现不复杂,也就是接收到 webhook 触发动作,解析内容,根据需要触发相应的流水线接口。截至目前(v1.17.0)zadig 的触发流水线接口已经可以正常使用了。

开始搬砖封装 Zadig API

首先封装一下 Zadig 的 API。为了方便使用,之前的弄了一个 go-zadig 项目(https://github.com/joker-bai/go-zadig),这两天将其做了更新,支持最新的 1.17.0 版本的 API。

主要增加了以下内容:

// 执行工作流type ExecWorkflowTaskOptions struct { WorkflowName string        `json:"workflow_name"` ProjectName  string        `json:"project_name"` Input        WorkflowInput `json:"input"`}type WorkflowInput struct { TargetEnv string         `json:"target_env,omitempty"` Build     ExecBuildArgs  `json:"build"` Deploy    ExecDeployArgs `json:"deploy"`}type ExecBuildArgs struct { Enabled     bool               `json:"enabled"` ServiceList []BuildServiceInfo `json:"service_list"`}type BuildServiceInfo struct { ServiceModule string           `json:"service_module"` ServiceName   string           `json:"service_name"` RepoInfo      []RepositoryInfo `json:"repo_info"` Inputs        []UserInput      `json:"inputs"`}type RepositoryInfo struct { CodehostName  string `json:"codehost_name"` RepoNamespace string `json:"repo_namespace"` RepoName      string `json:"repo_name"` Branch        string `json:"branch"` PR            int    `json:"pr"`}type UserInput struct { Key   string `json:"key"` Value string `json:"value"`}type ExecDeployArgs struct { Enabled     bool                `json:"enabled"` Source      string              `json:"source"` ServiceList []DeployServiceInfo `json:"service_list"`}type DeployServiceInfo struct { ServiceModule string `json:"service_module"` ServiceName   string `json:"service_name"` Image         string `json:"image"`}type ExecWorkflowTaskResponse struct { ProjectName  string `json:"project_name,omitempty"` WorkflowName string `json:"workflow_name,omitempty"` TaskID       int64  `json:"task_id,omitempty"`}func (w *WorkflowService) ExecWorkflowTask(opt *ExecWorkflowTaskOptions, options ...RequestOptionFunc) (*ExecWorkflowTaskResponse, *Response, error) { path := "openapi/workflows/product/task" req, err := w.client.NewRequest(http.MethodPost, path, opt, options) if err != nil {  return nil, nil, err } task := new(ExecWorkflowTaskResponse) resp, err := w.client.Do(req, &task) if err != nil {  return nil, resp, err } return task, resp, err}

这部分是执行标准工作流的接口。自定义工作流之前已经实现了,并没有什么变化。

开发 Http Server

由于 Zadig 原生不支持三方仓库的 Webhook,要实现不外乎两种:

自己修改 Zadig 源码,实现这部分功能。找一个中间商,由它来协调。

修改源码的好处是可以不需要再单独对数据这块做太多处理,直接用现成的。但我选择了后者,主要是因为菜,源码改起来费劲。

我使用的是 Uber 的 fx 框架。其实用什么框架不重要,本身的逻辑就很简单,我只是选了一个用起来比较简单和顺手的。

(1)定义数据结构
package entitytype ZadigWorkflowTask struct { ID            int    `json:"id"` ProjectName   string `json:"project_name"`   // 项目名 ServiceModule string `json:"service_module"` // 服务组件名称 ServiceName   string `json:"service_name"`   // 服务名 CodehostName  string `json:"codehost_name"`  // 代码源别名 RepoNamespace string `json:"repo_namespace"` // 仓库组名 RepoName      string `json:"repo_name"`      // 仓库名 WorkflowType  string `json:"workflow_type"`  // 工作流类型: product/custom JobName       string `json:"job_name"`       // 任务名 workflow_type为custom生效 JobType       string `json:"job_type"`       // 任务类型 workflow_type为custom生效 Registry      string `json:"registry"`       // 镜像仓库  workflow_type为custom生效}func (z *ZadigWorkflowTask) Table() string { return "zadig_workflow_task"}type ZadigWorkflowName struct { ID           int    `json:"id"` WorkflowName string `json:"workflow_name"` // workflow名 Branch       string `json:"branch"`        // 分支 ProjectName  string `json:"project_name"`  // 项目名 TargetEnv    string `json:"target_env"`    // 目标环境}func (z *ZadigWorkflowName) Table() string { return "zadig_workflow_name"}

我定义的比较简单,命名也比较随意。主要的字段就是 Zadig API 需要的字段,其他不需要的就没写了。

(2)实现 Zadig 触发标准和非标准流水线
package zadigimport ( "github.com/joker-bai/go-zadig" "joker-bai/go-webhook/config")type Zadig struct { client *zadig.Client}func NewZadig(cfg *config.Config) *Zadig { client, err := zadig.NewClient(cfg.ZadigConfig.Token, zadig.WithBaseURL(cfg.ZadigConfig.URL)) if err != nil {  panic(err) } return &Zadig{client: client}}// ExecProductWorkflowTask 执行标准工作流func (z *Zadig) ExecProductWorkflowTask(workflowName, projectName, targetEnv, serviceModule, serviceName, codehostName, repoNamespace, repoName, branch string) error { _, _, err := z.client.Workflow.ExecWorkflowTask(&zadig.ExecWorkflowTaskOptions{  WorkflowName: workflowName,  ProjectName:  projectName,  Input: zadig.WorkflowInput{   TargetEnv: targetEnv,   Build: zadig.ExecBuildArgs{    Enabled: true,    ServiceList: []zadig.BuildServiceInfo{     {      ServiceModule: serviceModule,      ServiceName:   serviceName,      RepoInfo: []zadig.RepositoryInfo{       {        CodehostName:  codehostName,        RepoNamespace: repoNamespace,        RepoName:      repoName,        Branch:        branch,       },      },     },    },   },   Deploy: zadig.ExecDeployArgs{    Enabled: true,    Source:  "zadig",   },  }, }) return err}// ExecCustomWorkflowTask 执行自定义工作流func (z *Zadig) ExecCustomWorkflowTask(projectName, workflowName, jobName, jobType, registry, serviceModule, serviceName, codehostName, repoNamespace, repoName, branch string) error { _, _, err := z.client.CustomWorkflow.CreateCustomWorkflowTask(&zadig.CreateCustomWorkflowTask{  ProjectName:  projectName,  WorkflowName: workflowName,  Inputs: []zadig.CreateCustomWorkflowTaskInput{   {    JobName: jobName,    JobType: jobType,    Parameters: zadig.CreateCustomWorkflowTaskParameters{     Register: registry,     ServiceList: []zadig.ServiceList{      {       ServiceModule: serviceModule,       ServiceName:   serviceName,       RepoInfo: []zadig.RepoInfo{        {         CodehostName:  codehostName,         RepoNamespace: repoNamespace,         RepoName:      repoName,         Branch:        branch,        },       },      },     },    },   },  }, }) return err}

这里对工作流的 API 进行了取舍,根据实际情况选择需要的字段。

(3)实现 service 方法
package serviceimport ( "context" "fmt" "github.com/sirupsen/logrus" "go.uber.org/fx" "joker-bai/go-webhook/config" "joker-bai/go-webhook/infrastructure/db" "joker-bai/go-webhook/internal/domain/entity" "joker-bai/go-webhook/pkg/zadig")// 获取并处理Codeup的Webhooktype CodeupWebhookService struct { logger *logrus.Logger cfg    *config.Config db     *db.DataBase}var RegCodeupWebhookService = fx.Provide(func(logger *logrus.Logger, cfg *config.Config, db *db.DataBase) *CodeupWebhookService { return &CodeupWebhookService{  logger: logger,  cfg:    cfg,  db:     db, }})// ExecZadigWorkflowTask 触发执行zadig的工作流func (c *CodeupWebhookService) ExecZadigWorkflowTask(ctx context.Context, repoName, branch string) error { client := zadig.NewZadig(c.cfg) // 从数据库中获取数据 dbClient := c.db.Master.WithContext(ctx) var workflowTask entity.ZadigWorkflowTask workflowTaskRes := dbClient.Model(&workflowTask).Where("repo_name = ?", repoName).First(&workflowTask) if workflowTaskRes.Error != nil {  return workflowTaskRes.Error } // 从数据库获取项目和工作流信息 var flowName entity.ZadigWorkflowName workflowNameRes := dbClient.Model(&flowName).Where("branch = ? and project_name = ?", repoName, workflowTask.ProjectName).First(&flowName) if workflowNameRes.Error != nil {  return workflowNameRes.Error } // 判断workflow的类别 if workflowTask.WorkflowType == "product" {  return client.ExecProductWorkflowTask(   flowName.WorkflowName,   workflowTask.ProjectName,   flowName.TargetEnv,   workflowTask.ServiceModule,   workflowTask.ServiceName,   workflowTask.CodehostName,   workflowTask.RepoNamespace,   workflowTask.RepoName,   branch,  ) } else if workflowTask.WorkflowType == "custom" {  return client.ExecCustomWorkflowTask(   workflowTask.ProjectName,   flowName.WorkflowName,   workflowTask.JobName,   workflowTask.JobType,   workflowTask.Registry,   workflowTask.ServiceModule,   workflowTask.ServiceName,   workflowTask.CodehostName,   workflowTask.RepoNamespace,   workflowTask.RepoName,   branch,  ) } else {  return fmt.Errorf("未匹配workflow类型") }}

这里从数据库获取需要的信息,然后根据不同的工作流类型执行不同的接口。

(4)实现 controller 方法
package applicationimport ( "fmt" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "go.uber.org/fx" "joker-bai/go-webhook/internal/core/base" "joker-bai/go-webhook/domain/service" "strings" "time")var regCodeupWebhookApplication = fx.Provide(NewCodeupWebhookController)type CodeupWebhookController struct { logger  *logrus.Logger service *service.CodeupWebhookService}type CodeupWebhook struct { After             string     `json:"after"` AliyunPk          string     `json:"aliyun_pk"` Before            string     `json:"before"` CheckoutSha       string     `json:"checkout_sha"` Commits           []Commits  `json:"commits"` ObjectKind        string     `json:"object_kind"` ProjectID         int        `json:"project_id"` Ref               string     `json:"ref"` Repository        Repository `json:"repository"` TotalCommitsCount int        `json:"total_commits_count"` UserEmail         string     `json:"user_email"` UserExternUID     string     `json:"user_extern_uid"` UserID            int        `json:"user_id"` UserName          string     `json:"user_name"`}type Author struct { Email string `json:"email"` Name  string `json:"name"`}type Commits struct { Author    Author    `json:"author"` ID        string    `json:"id"` Message   string    `json:"message"` Timestamp time.Time `json:"timestamp"` URL       string    `json:"url"`}type Repository struct { Description         string `json:"description"` GitHTTPURL          string `json:"git_http_url"` GitSecondaryHTTPURL string `json:"git_secondary_http_url"` GitSecondarySSHURL  string `json:"git_secondary_ssh_url"` GitSSHURL           string `json:"git_ssh_url"` Homepage            string `json:"homepage"` Name                string `json:"name"` URL                 string `json:"url"` VisibilityLevel     int    `json:"visibility_level"`}func NewCodeupWebhookController(logger *logrus.Logger, service *service.CodeupWebhookService) *CodeupWebhookController { return &CodeupWebhookController{  logger:  logger,  service: service, }}// DoCodeupWebhook 获取Codeup 代码webhook的Bodyfunc (c *CodeupWebhookController) DoCodeupWebhook(ctx *gin.Context) { output := base.NewResponse(ctx) var param CodeupWebhook err := ctx.ShouldBindJSON(¶m) if err != nil {  output.Error(10000, err.Error())  return } // 获取repo_name,repo_namespace,branch repoName := param.Repository.Name branch := strings.Split(param.Ref, "/")[2] if err := c.service.ExecZadigWorkflowTask(ctx, repoName, branch); err != nil {  c.logger.Error(err.Error())  output.Error(502, "执行workflow失败") } output.Success(gin.H{  "data": "ok", })}

这部分就更简单了,从 Webhook 中获取数据,然后调 service 去执行即可。

最后就是增加路由了,这部分就不用展示了。

搬砖结束

搬砖完成过后就是对自己开发的 HTTP Server 进行验证了。

整个思路和开发的工作量都不大,上面的代码还有很多地方需要去调整的,如果有相同需求的可以自己去实现,我仅仅是做了一个 demo。

通过引入中间商的方式来实现自己的需求的优点是比较简单,不需要去看或者兼容其他的代码,只需要实现自己的逻辑,缺点就是数据这一块需要单独去处理,比较麻烦。

三方仓库如何实现Zadig流水线自动触发_播报

2023-05-09

世界即时:挖呀挖呀挖!快来福州新区解锁夏日赶海行动!

2023-05-09

一季度 271.84亿元!经济强区开局稳 全球快消息

2023-05-09

OpenAI 推出 Shap E:基于文本数秒内生成高质量 3D 模型

2023-05-09

一案一析| 强对流天气“出没”,如何“全身而退”

2023-05-09

强化高端引领加快发展先进制造业 当前看点

2023-05-09

业绩双降的居然之家,居然要靠涨租金“自救”…… 世界热门

2023-05-09

职业教育“接听”急救培训“接生”

2023-05-09

解放军报:美“选择性核扩散”严重危害世界和平

2023-05-09

5月8日基金净值:华泰柏瑞品质成长混合A最新净值0.6764,涨1.38%

2023-05-09

创新药在华正式获批 用于治疗I型神经纤维瘤病儿童患者_全球热门

2023-05-09

生态美、产业美、生活美!听,山东奏响了这些好声音 消息

2023-05-09

焦点讯息:机缘巧合什么意思_机缘巧合的解释

2023-05-09

真外挂加持,腾讯ROG游戏手机 7 Pro体验|天天速讯

2023-05-08

广西职校学生洗澡时身亡 校方通报处理中!

2023-05-08

nfc怎么复制门禁卡(nfc怎么复制门禁卡华为)-全球热头条

2023-05-08

热文:篮球——CBA总决赛:浙江稠州金租对阵辽宁本钢(1)

2023-05-08

关注:楼市大消息!两部门重拳出手,严禁操纵这项收费

2023-05-08

【独家】泽连斯基签署法令,将5月9日卫国战争胜利日改为“欧洲日”

2023-05-08

业绩增长领跑家电行业 小熊电器李一峰:多维度创新支撑成长_天天观热点

2023-05-08

【环球热闻】美国得州石油化工厂火灾扑救进入第三天 消防废水被直接排入附近航道

2023-05-08

央媒眼中的吉林(2023.5.8)︱清洁能源 “新粮道”

2023-05-08

银保监会:核准关文杰华夏银行行长任职资格 环球观点

2023-05-08

环球最资讯丨ANSYS Mechanical 软件简介

2023-05-08

热点在线丨岳阳县卫健局召开党建工作会议暨党建品牌创建工作会议

2023-05-08

快资讯丨「桃李先锋」李官镇开展党的二十大精神第二轮集中学习

2023-05-08

海欣食品:002702海欣食品调研活动信息20230508|全球播资讯

2023-05-08

全球速讯:米素除醛王牌重磅登场,为千家万户守卫健康家居空间!

2023-05-08

世界观点:【BL推文】《玉米地》作者:狄醉山 高字母/强制

2023-05-08

钢人裁掉了三名球员其中包括泰格雷斯-报资讯

2023-05-08

警探号|女子跳桥轻生 警民联手救起

2023-05-08

法国面积和人口是多少(法国人口和面积是多少) 最新消息

2023-05-08

【全球快播报】百度CTO王海峰团队摘获吴文俊人工智能科技进步奖特等奖

2023-05-08

【环球新要闻】今日南财市场情绪指数为30.7,市场投资热度明显降低

2023-05-08

手机屏幕中间有一条线是什么原因_手机屏幕中间有一条线

2023-05-08

【世界播资讯】呵护眼睛 小心劣质太阳镜危害健康

2023-05-08

如何真正做有价值的科研?听“茶叶院士”陈宗懋的答案 世界观热点

2023-05-08

环球关注:oppo和vivo是上市公司吗_oppovivo是一家公司吗

2023-05-08

焦点热议:“水果界爱马仕”价格“腰斩”,百元内拿下一整个!“水果班列”来了,这些热带水果开始大量上市

2023-05-08

报道:意天空:丹布罗西奥有望在周中欧冠复出,戈森斯需等到次回合

2023-05-08

天津外地车高峰时段通行证一年可以办几次?-当前视讯

2023-05-08

夯什么内涵_夯什么意思

2023-05-08

81分!阿森纳近15年来英超联赛积分首次超过80分-环球精选

2023-05-08

settings是什么意思翻译成中文_settings是什么意思

2023-05-07

环球最新:一季度重庆金融运行“成绩单”出炉 主要指标稳中向好

2023-05-07

报道:建月球基地的玻璃有了?中国科学家月壤最新发现!

2023-05-07

小孩咳嗽按摩哪个部位图解_小孩咳嗽按摩哪个部位图|每日视讯

2023-05-07

【环球速看料】关于菊花的知识或资料 关于菊花的资料

2023-05-07

容灾备份和双机热备_容灾备份

2023-05-07

简讯:安泰科技:公司具有非晶产业平台和技术开发平台优势,一直从事包括非晶、纳米晶相关产品的研发

2023-05-07

提升供给体系对国内需求的适配性:以高质量供给创造引领新需求

2023-05-07

天津2023游船演出季开幕

2023-05-07

全球今头条!公示!事关南海区民办中小学政策直招

2023-05-07

外贸中SO是什么意思?_外贸中so是什么意思 热消息

2023-05-07

连续强降雨致村庄被淹人员被困 江西新干县紧急开展救援

2023-05-07

天天即时看!在人间高尔基读后感_在人间高尔基

2023-05-07

环球播报:巴菲特谈投资派拉蒙:流媒体业务仍然充满挑战

2023-05-07

险资一季度投资标的曝光!追风“中特估” 国寿猛减银行股 讯息

2023-05-07

全球滚动:神武刷官职你们刷了多久时间_神武官兵捉贼有什么技巧怎么玩

2023-05-07

中央气象台:云南广西广东海南岛等地将有强对流天气-今日热议

2023-05-07

公交借道背后见管理

2023-05-07

百事通!广西贵港:武警官兵立夏练兵忙

2023-05-07

每日消息!SM城市广场品牌介绍_SM城市广场购物中心

2023-05-07

云南专升本志愿填报密码忘记了怎么办-当前最新

2023-05-06

当前信息:桂林象山区:清廉景区建设为南溪河水系治理保驾护航

2023-05-06

会宁:找准治理“小切口”保障出行“大安全”-世界速读

2023-05-06

槽钢型号尺寸对照表_槽钢型号

2023-05-06

世界速读:2023年5月5日重质纯碱价格最新行情预测

2023-05-06

全球热讯:买的速冻粽子是熟的吗

2023-05-06

世界速讯:数字赋能 全民共享——青海省2023年全民数字素养与技能提升月活动启动

2023-05-06

广西初步测算耕地土壤碳汇潜力约8355万吨|全球今热点

2023-05-06

环球要闻:5月6日江苏地区醋酸市场整理运行

2023-05-06

中国航母是“宣传片”?专家:山东舰编队首赴西太海域可看作正面回应 天天观天下

2023-05-06

邯郸V视丨【聚焦省运会】省运会自由式小轮车比赛顺利收官

2023-05-06

【全球速看料】“微信警察”上线!遂宁“D警官”服务好贴心

2023-05-06

漏绘南海诸岛、钓鱼岛等,东渡海关查获350套“问题地图”

2023-05-06

弄瓦之喜的意思 弄瓦之喜的故事内容

2023-05-06

阿里云自动驾驶平台为何如此拉胯? 世界消息

2023-05-06

环球快消息!伊能静个人资料年龄 尹能静个人资料

2023-05-06

3.9元卖咖啡,瑞幸听了都摇头|全球播报

2023-05-06

热议:电影《长空之王》发布“歼-20霸气驱敌”正片片段,上映第八天单日票房1473万

2023-05-06

股票中签号查询网站_股票中签号查询 环球速讯

2023-05-06

盛极一时的“小世界杯”,终于迎来复兴?_环球最资讯

2023-05-06

“五一”假期掀消费热 多项数据创新高带动中国经济回暖_资讯推荐

2023-05-06

先涨2000元 再涨1.9万元!特斯拉价格频繁变动 国产车企出路何在? 环球热议

2023-05-06

2023年一季度“安徽好人”榜单揭晓

2023-05-06

市场预计美联储今年有75基点降息!

2023-05-06

环球热头条丨孝女彩金在线观看电影 孝女彩金电影完整版下载

2023-05-06

王诗龄离开李湘后,化烟熏妆吃高级餐厅

2023-05-06

作文晚霞80字到100字(合集24篇)_当前播报

2023-05-06

北京73宗宅地推介亮相 “多频少量”均衡供应 天天观速讯

2023-05-06

传承古风古韵,并通过创造性转化赋予更多人文温度 舟山螺钿工艺“时尚出圈”_全球快播

2023-05-06

魂·魄_关于魂·魄简述 精彩看点

2023-05-06

多公司触碰“AI” 二级市场表现抢眼 世界热讯

2023-05-05

高安城区3块住宅用地即将拍卖!

2023-05-05

华泰证券(06886):华泰国际为华泰国际财务发行5100万港元票据提供担保

2023-05-05

王导:黄金2010现价直接多,目标2035

2023-05-05

18个县区首次开展!徐汇医疗队助力萨迦学生口腔卫生全覆盖检查

2023-05-05

益阳市气象局发布暴雨黄色预警【Ⅲ级/较重】【2023-05-05】|时快讯

2023-05-05

天安新材: 感谢您对公司关注!公司建筑陶瓷的自制产品及外协产品的具体情况请查阅公司2022年年度报告

2023-05-05