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

推薦する

itldc: 夏の 50% オフ プロモーション、最低 16 ユーロ/年、シンガポールと米国を含む 11 のデータセンターでトラフィック無制限の VPS

itldc の夏のプロモーション: すべての VPS が 50% オフ。初回支払いのみ、更新は通常価...

北京インターネット監視センターは、一時的にアクセス不能になっていた「茶観坊」ウェブサイトの調査を開始した。

北京新聞(記者 林葉) 北京新聞は10月21日と22日、インターネット上に「ホテル予約チェック」のウ...

2021 年にクラウド コンピューティング分野にはどのような新たな変化があるでしょうか?

過去数年間、クラウドはビジネス変革と IT インフラストラクチャの近代化のバックボーンとして登場しま...

Baidu のメジャーアップデートにより、検索結果の視覚的エクスペリエンスが大幅に向上

今日午後5時頃、Baiduの検索結果が以前と違うことに気づきました。よく見ると、検索結果のURLが簡...

A2hosting - 仮想ホストが 51% オフ / ピュア SSD / 無制限のウェブサイト構築 / オプションのコンピュータ ルーム 3 つ

2003年から運営しているホスティングプロバイダーのA2hostingが、仮想ホスト向けに51%割引...

ウェブホスティング: ウェブサイト最適化の基礎

ウェブマスターの友人のほとんどは SEO を知っています。彼らはウェブサイトを最適化すると同時に、外...

ハーブティーの戦いで、王老吉が佳多宝を倒すために使った最も強力な技は何でしたか?

月収10万元の起業の夢を実現するミニプログラム起業支援プラン要約:佳多宝の衰退は、ハーブティー業界や...

チュートリアル: VPS の更新手順

この記事を使って、BandwagonHost の更新問題について皆さんに説明します。Bandwago...

Linodeはユーザーにハードドライブの20%の無料アップグレードを提供

Linode は VPS 業界ではよく知られたブランドであり、それを使用したことがある人だけがその ...

2.1.2 利点

2.1.2 利点Yii は学習も使用も簡単です。ユーザーは、事前に新しいアーキテクチャやテンプレート...

消費者を騙すマーケティング手法

マーケティングの核心は戦略と方法にあり、ユーザーの心理を研究し、適切なマーケティング方法を提供します...

中小企業のネットワークマーケティングにおけるユーザー行動習慣の分析

序文: 方向が間違っていると、一生懸命努力すればするほど、目標から遠ざかってしまいます。電子商取引の...

hostodo-$30/年/KVM/512m メモリ/15g ハードディスク/1T トラフィック/solusvm

hostodo.com は、KVM 仮想化、solusvm パネル、1000M ポートに基づく新しい...

6.22 から 6.28 への進化から何がわかりましたか?

ウェブマスターグループでは、この2つの日に何が起こったのかが間違いなく話題になっています。私は長い間...

CEOがクラウドベースのソリューションで将来性を求める理由

増大する顧客の需要を満たすために、企業はビジネスをクラウド プラットフォームに移行する必要があります...