自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三方倉庫如何實現(xiàn)Zadig流水線自動觸發(fā)

云計算 云原生
有同學可能會問,都用云效了,為什么不直接用它的 AppStack,還要用 Zadig?

最近因為公司的產(chǎn)研調(diào)整,決定將代碼倉庫從本地的 Gitlab 遷移到云效的 Codeup,不是 Gitlab 不夠好,而是 Codeup 在度量、安全等方面比原生的 Gitlab 要好,再則公司的產(chǎn)研管理也遷移到了云效,也為了統(tǒng)一化管理。

有同學可能會問,都用云效了,為什么不直接用它的 AppStack,還要用 Zadig?

AppStack 還處于發(fā)展階段,還有以下問題不適合我們現(xiàn)階段的需求:

  1. AppStack 不支持管理私有云 Kubernetes 集群(沒有公網(wǎng)入口)。
  2. AppStack 不支持 Helm 類應(yīng)用,改造工作比較大。

再則,我也是 Zadig 開源產(chǎn)品的忠實粉絲~~!

但是,Zadig 對非標準的代碼倉庫的支持力度有限,比如:

  1. 非標準代碼倉庫不支持列出倉庫列表,需要自己手動填寫
  2. 非標準代碼倉庫創(chuàng)建的流水線原生不支持 Webhook 觸發(fā)

經(jīng)過綜合考慮,手動填寫代碼倉庫信息以及不支持 Webhook 并不影響整體的使用,只是會影響部分項目的工作效率。

但是,為了最小程度上影響原有的產(chǎn)研節(jié)奏,我還是準備自己實現(xiàn)三方倉庫的 Webhook 觸發(fā) Zadig 流水線。因為本身也不復雜。

整體思路

圖片

實現(xiàn)不復雜,也就是接收到 webhook 觸發(fā)動作,解析內(nèi)容,根據(jù)需要觸發(fā)相應(yīng)的流水線接口。截至目前(v1.17.0)zadig 的觸發(fā)流水線接口已經(jīng)可以正常使用了。

開始搬磚

封裝 Zadig API

首先封裝一下 Zadig 的 API。為了方便使用,之前的弄了一個 go-zadig 項目(https://github.com/joker-bai/go-zadig),這兩天將其做了更新,支持最新的 1.17.0 版本的 API。

主要增加了以下內(nèi)容:

// 執(zhí)行工作流
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
}

這部分是執(zhí)行標準工作流的接口。自定義工作流之前已經(jīng)實現(xiàn)了,并沒有什么變化。

開發(fā) Http Server

由于 Zadig 原生不支持三方倉庫的 Webhook,要實現(xiàn)不外乎兩種:

  1. 自己修改 Zadig 源碼,實現(xiàn)這部分功能。
  2. 找一個中間商,由它來協(xié)調(diào)。

修改源碼的好處是可以不需要再單獨對數(shù)據(jù)這塊做太多處理,直接用現(xiàn)成的。但我選擇了后者,主要是因為菜,源碼改起來費勁。

 我使用的是 Uber 的 fx 框架。其實用什么框架不重要,本身的邏輯就很簡單,我只是選了一個用起來比較簡單和順手的。

(1)定義數(shù)據(jù)結(jié)構(gòu)

package entity

type ZadigWorkflowTask struct {
 ID            int    `json:"id"`
 ProjectName   string `json:"project_name"`   // 項目名
 ServiceModule string `json:"service_module"` // 服務(wù)組件名稱
 ServiceName   string `json:"service_name"`   // 服務(wù)名
 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"`       // 任務(wù)名 workflow_type為custom生效
 JobType       string `json:"job_type"`       // 任務(wù)類型 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"`    // 目標環(huán)境
}

func (z *ZadigWorkflowName) Table() string {
 return "zadig_workflow_name"
}

我定義的比較簡單,命名也比較隨意。主要的字段就是 Zadig API 需要的字段,其他不需要的就沒寫了。

(2)實現(xiàn) Zadig 觸發(fā)標準和非標準流水線

package zadig

import (
 "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 執(zhí)行標準工作流
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 執(zhí)行自定義工作流
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 進行了取舍,根據(jù)實際情況選擇需要的字段。

(3)實現(xiàn) service 方法

package service

import (
 "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的Webhook

type 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 觸發(fā)執(zhí)行zadig的工作流
func (c *CodeupWebhookService) ExecZadigWorkflowTask(ctx context.Context, repoName, branch string) error {
 client := zadig.NewZadig(c.cfg)

 // 從數(shù)據(jù)庫中獲取數(shù)據(jù)
 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
 }

 // 從數(shù)據(jù)庫獲取項目和工作流信息
 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類型")
 }
}

這里從數(shù)據(jù)庫獲取需要的信息,然后根據(jù)不同的工作流類型執(zhí)行不同的接口。

(4)實現(xiàn) controller 方法

package application

import (
 "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的Body
func (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, "執(zhí)行workflow失敗")
 }

 output.Success(gin.H{
  "data": "ok",
 })
}

這部分就更簡單了,從 Webhook 中獲取數(shù)據(jù),然后調(diào) service 去執(zhí)行即可。

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

搬磚結(jié)束

搬磚完成過后就是對自己開發(fā)的 HTTP Server 進行驗證了。

整個思路和開發(fā)的工作量都不大,上面的代碼還有很多地方需要去調(diào)整的,如果有相同需求的可以自己去實現(xiàn),我僅僅是做了一個 demo。

通過引入中間商的方式來實現(xiàn)自己的需求的優(yōu)點是比較簡單,不需要去看或者兼容其他的代碼,只需要實現(xiàn)自己的邏輯,缺點就是數(shù)據(jù)這一塊需要單獨去處理,比較麻煩。

責任編輯:姜華 來源: 運維開發(fā)故事
相關(guān)推薦

2017-03-02 14:12:13

流水線代碼Clojure

2021-06-28 06:32:46

Tekton Kubernetes Clone

2011-10-19 08:04:12

2022-07-18 06:05:28

Gitlab流水線

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-05-10 15:08:00

Pipeline設(shè)計模式

2013-06-06 09:31:52

2017-02-28 15:40:30

Docker流水線Azure

2021-11-08 07:41:16

Go流水線編程

2024-01-07 12:47:35

Golang流水線設(shè)計模式

2021-06-26 14:22:34

Tekton流水線Kubernetes

2022-01-26 08:12:42

Jenkins開源流水線

2021-04-29 08:55:54

GitLabDevOps項目

2023-08-18 10:24:52

GitLabCI 流水線

2021-12-24 08:02:48

GitLabCI模板庫流水線優(yōu)化

2021-06-18 05:48:02

Tekton DevopsKubernetes

2023-09-27 08:24:49

2025-04-07 04:21:00

2024-04-03 09:55:56

代碼pipeline項目

2021-01-05 08:39:51

容器前端流水線
點贊
收藏

51CTO技術(shù)棧公眾號