サードパーティのウェアハウスで Zadig パイプラインの自動トリガーを実現する方法

サードパーティのウェアハウスで Zadig パイプラインの自動トリガーを実現する方法

最近、同社の生産と研究の調整により、コードリポジトリをローカルの Gitlab から Yunxiao の Codeup に移行することが決定されました。 Gitlab が十分ではないというわけではありませんが、測定とセキュリティの点では Codeup がネイティブの Gitlab よりも優れています。さらに、同社の生産・研究管理もYunxiaoに移行し、統一的な管理が図られています。

Cloud Effect を使用しているのだから、Zadig ではなくその AppStack を使用すればいいのでは、と疑問に思う学生もいるかもしれません。

AppStack はまだ開発段階にあり、現在のニーズに適さない次のような問題があります。

  1. AppStack は、プライベート クラウド Kubernetes クラスター (パブリック ネットワーク アクセスなし) の管理をサポートしていません。
  2. AppStack は Helm タイプのアプリケーションをサポートしておらず、変換作業が比較的大きくなります。

また、私はZadigオープンソース製品の大ファンでもあります~~!

ただし、Zadig では次のような非標準コード リポジトリのサポートが制限されています。

  1. 非標準コード リポジトリはリポジトリのリストをサポートしていないため、手動で入力する必要があります。
  2. 非標準コードリポジトリで作成されたパイプラインは、Webhook トリガーをネイティブにサポートしていません。

総合的に検討した結果、コードリポジトリ情報を手動で入力し、Webhook をサポートしないことは、全体的な使用には影響しませんが、一部のプロジェクトの作業効率にのみ影響します。

ただし、本来の制作や研究のリズムへの影響を最小限に抑えるために、サードパーティのウェアハウスの Webhook を実装して、Zadig パイプラインを自分でトリガーする予定です。複雑ではないからです。

全体的なアイデア

実装は複雑ではなく、Webhook トリガー アクションを受信し、コンテンツを解析し、必要に応じて対応するパイプライン インターフェイスをトリガーするだけです。現在 (v1.17.0)、Zadig のトリガー パイプライン インターフェイスは正常に使用できます。

レンガを動かし始める

Zadig API のラッピング

まず、Zadig の API をカプセル化します。使いやすさを考慮して、go-zadig プロジェクト (https://github.com/joker-bai/go-zadig) を作成し、過去 2 日間で更新して、API の最新バージョン 1.17.0 をサポートしました。

主な追加内容は次のとおりです。

 // 执行工作流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 サーバーの開発

Zadig はサードパーティ リポジトリの Webhook をネイティブにサポートしていないため、実装するには 2 つの方法があります。

  1. この機能を実装するには、Zadig ソース コードを自分で変更します。
  2. 調整する仲介者を見つけます。

ソースコードを変更する利点は、データに対して個別に多くの処理を実行する必要がなく、既製のものをそのまま使用できることです。しかし、私は後者を選択しました。主な理由は、私にとって初心者だったことと、ソース コードを変更するのが難しかったためです。

 私はUberのfxフレームワークを使用しています。実際のところ、どのフレームワークを使用するかは重要ではありません。ロジック自体は非常に単純です。よりシンプルで使いやすいものを選択しました。

(1)データ構造を定義する

package entity type 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 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 执行标准工作流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)サービス方式の実装

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 触发执行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)コントローラメソッドの実装

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, "执行workflow失败") } output.Success(gin.H{ "data": "ok", }) }

この部分はさらに簡単です。 Webhook からデータを取得し、サービスを呼び出して実行するだけです。

最後のステップはルーティングを追加することですが、ここでは説明しません。

レンガ造りは終わった

レンガの移動が完了したら、開発した HTTP サーバーを検証します。

全体的なアイデアや開発作業量はそれほど大きくありません。上記のコードにはまだ調整が必要な箇所が多数あります。同じ要件がある場合は、自分で実装できます。デモを作りました。

ニーズを満たすために仲介業者を導入する利点は、それが比較的簡単なことです。他のコードを参照したり互換性を持たせる必要はありません。独自のロジックを実装するだけで済みます。デメリットとしては、データを個別に扱う必要があり、面倒なことです。

<<:  5G時代のエッジコンピューティングとは?

>>:  ヒープ メモリ: Java プログラムの「宝物」、そこに何が隠されているかご存知ですか?

推薦する

B2C電子商取引企業が海外のオンラインゴールドラッシュに群がる:国内貿易競争は激しすぎる

南都地図:陳芳国内貿易の競争が激しすぎるため、Vancl、JD.com、Mengbashaなどが対外...

OpenStack サーバーを管理するための 5 つのオープンソース ツール

OpenStack は、市販のハードウェア上で実行される Infrastructure as a S...

ramnode-VPS 最大 58% オフ / 再び IP が無料

Ramnode は非常に良心的な企業だと言えます。現在、約 200 台のサーバーがあり、スタッフは ...

Baidu がなければ、どのようにウェブサイトを運営するのでしょうか?

6月22日に百度が大量のサイトをK-outし始めたとき、多くの草の根ウェブマスターたちはこの厳しい夏...

Baidu で新しいウェブサイトの内部ページを数秒でインデックスする方法

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますBaidu...

なぜ書店が必要なのでしょうか?

書店を開こうとする人は多く、書店で本を読む人は多くても、オンラインで購入している。多くの書店は損益分...

伝統的な地域メディアが一斉に変革の時代を先導する

ある人々にとって、変革は非常にファッショナブルでクールな言葉ですが、ある人々にとって、変革は諦めるこ...

99Cloud Edge MEPが「中国エッジクラウド研究」レポートの代表的製品に選ばれました

最近、世界的に有名な市場調査機関であるIDCが初めて「中国エッジクラウド調査、2021」レポートを発...

uuuvps: 春節プロモーション、香港 cn2 vps は年間 168 元から、複数の構成、無制限のトラフィック

uuuvps (Sanyouyun、登録番号 2869262、ID についてはここをクリック) は、...

共同購入の救済:ハンガー・ゲームの生存者

中国の共同購入業界のカードはついに片付けられ、ゲームはついに最終段階に到達した。かつて最大の共同購入...

保守的な豆板と革新的な知乎

Douban とZhihu は、中国のインターネット コミュニティ製品のさまざまな発展の道筋を記録し...

最近サイトが不安定になっています

先週の金曜日から、ホスト猫は他の人、CC+DDに攻撃されています。中国の商人は非常にひどいので、問題...

華雲データ西北本部が西県新区に上陸し、国家クラウドコンピューティング研究所を建設

[[429612]] 2021年10月15日、華雲データと陝西省西県新区開発建設管理委員会は、「秦創...

2018 年第 4 四半期の低価格 VPS ランキング トップ 10

低価格 VPS リストの第 4 四半期のランキングが発表され、順位は次のようになりました。1 位 r...

ケーススタディ |ホスピタリティ、エネルギー、食品、農業などの業界におけるクラウド移行パスのまとめ(パート 2)

「クラウド+」時代の到来により、クラウド コンピューティングを通じて企業のデジタル変革を実現すること...