サードパーティのウェアハウスで 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 プログラムの「宝物」、そこに何が隠されているかご存知ですか?

推薦する

80vps: 香港無制限トラフィック VPS、セラデータセンター、生涯 50% オフ特別プロモーション

80vpsは2011年から運営されており、比較的古い中国の企業とされています。主にXENとKVM仮想...

推奨:ultravps-1g メモリ/15g SSD/4IP/1T トラフィック/ラスベガス

おそらくほとんどの人は ultravps についてよく知らないでしょうから、ここで簡単に紹介します。...

CNNIC証明書をクリアする方法

過去1〜2週間、CNNICのCA証明書の問題についてオンラインで多くの議論がありました。しかし、IT...

JD Cloud: 2Gメモリ/2コア/40Gクラウドディスク/4M帯域幅、88元/年、468元/3年、北京/江蘇

JD Cloudは現在、クラウドサーバーの特別プロモーションを実施しています。北京データセンターと江...

インターネットの未来はどうなるのか?「スーパーエンジン」がインターネットにインスピレーションを与える

ソン・ソンが描いた多くの人々、特にベテランネットユーザーは、1990年代初頭、中関村の街を歩いている...

バーチャルカード: Alipay チャージ + PayPal の認証 + Googleplay バーチャルクレジットカード

本日ご紹介するのは、バーチャルカードです。一言で言えば、バーチャルカードは使い過ぎない、非常に簡単に...

SEOではトリックよりもトリックがないと言われるのはなぜか

月収10万元の起業の夢を実現するミニプログラム起業支援プラン私はずっとSEOに興味があり、徐々にいく...

ハンハン氏による百度ライブラリに対する訴訟は、SEOにとって祝福か呪いか?

みなさんこんにちは。私はみなさんの古い友人、魏東東です。実際、業界が現在最も懸念しているのは、ハンハ...

Xiaomiのインターネット思考モデルとマーケティングアプローチについての私の理解

春節から今まで、ようやくXiaomiのスマホを手に入れました。いや、違います。実は何度か手に入れよう...

nodepop-512M メモリ/10G ハードディスク/月額 6 ドル/HE ホーム フリーモント データ センター

nodepop.com は新しく設立された小規模なホスティングサービス会社です。現在は規模が小さく、...

hostkvm のロサンゼルス cn2 vps、バックホールの簡単なレビュー: 中国電信 AS4809、中国聯通 AS9929、中国移動直接接続

Hostkvm は、誰もが好むアジアのデータセンターの VPS だけでなく、米国ロサンゼルスの非常に...

中国ブランドデーに、企業はどのようにしてインターネット上で自社ブランドを確立できるのでしょうか?

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスブランドは、常に生産者と...

Donkey Brother の SEO 成長パス

SEO 担当者は誰でも、混乱、当惑、困惑、そして成長の時期を経験します。今日は、私自身の SEO 成...

「こんにちは、李華英」という投稿が、昔の写真の波を引き起こした。テンセント微笑みがあなたを時空を超えて、昔の写真の笑顔を取り戻します ?

最近、春節映画「こんにちは、李華英」の人気と、映画に登場した賈玲の母親の若い頃の昔の写真により、多く...

ウェブサイトのキーワードパフォーマンス分析: ランキング表示とトラフィッククリック

みなさんこんにちは。私はMuzi Chengzhouです。ウェブサイトの最適化とプロモーションでは、...