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

推薦する

Shardhost - 月額 7 ドル 1G KVM | 2G OpenVZ

Shardhost は、2011 年 6 月に英国で登録された小規模な VPS プロバイダーです (...

ゼロから始めて、2週間でファンを5,000人に増やしましょう

私は過去 2 週間、Weibo をゼロから始めて、フォロワーを素早く増やす方法を学びながら、いろいろ...

yalo-$5/1g メモリ/200g ハードディスク/10T トラフィック/ノースカロライナ

yaloがホストキャットに登場するのは2回目。昨年設立され、openvz仮想化をベースにしている。最...

Hostus - ロサンゼルス データセンター、VPS の簡単なレビュー、[年間 10 ドルの支払いの VPS]

Hostcatは以前、Hostusのダラス、ロンドン、香港のデータセンターのVPSで簡単なテストを実...

maple-hosting: オランダの苦情耐性サーバー、$389、AMD Epyc 7313/64g メモリ/16T SSD/1Gbps 専用フルデュプレックス

Maple-hosting (2008~) は、オランダの有名なサーバープロバイダーです。オランダの...

Webmaster.com からの毎日のレポート: Sina Weibo の開設が加速。中国のドメイン名は独立して運営されている

1. iOSアプリは65万に達し、Androidアプリの数もそれに迫っている7月25日、アップルは第...

クラウド間の移行に必要な 7 つの重要なステップ

企業のビジネスがクラウド プラットフォーム間で移行する場合、少なくとも短期的には、製品やテクノロジー...

一つだけ言わせてください: ウェブサイトを最適化する際に心配すべき4つの不要な領域

私は数年間SEOに取り組んでおり、20〜30以上のウェブサイトを最適化してきました。継続的な学習と要...

ウェブサイトが降格されたかどうかを確認する方法

最近、SEOに関する記事をたくさん読んでいますが、内容は多岐にわたります。特に最近のGreen Ra...

SEOトレーニング市場の氾濫と対処戦略を共有する

SEO 技術は以前ほど普及しておらず、さまざまな理由で Baidu によって排除されるウェブサイトが...

siberdc: 月額 3 ドル、トルコ VPS (トラフィック無制限)、1G メモリ/2 コア/30g SSD/1Gbps 帯域幅

トルコの商人であるsiberdcは2011年に設立されました。主にトルコの高防御事業を運営しており、...

理想的なIaaS契約を策定する方法

特定のデータ センター処理機能にインフラストラクチャ アズ ア サービス (IaaS) の使用を検討...

エッジオブジェクトストレージが分散コンピューティングをサポートする方法

オブジェクト ストレージは、エッジ市場をめぐる戦いにおいて主要な役割を果たしており、高度に分散された...

企業がパブリッククラウドを導入すべき10の理由

過去 18 か月間、テクノロジーは多くの企業にとって救世主であることが証明されました。パンデミックが...