如何取得 GitLab 另一個 Pipeline 的 artifacts

介紹如何透過 GitLab API 在 Upstream 取得 Downstream 的 artifact。

大家都熟悉在 repo 裏面建立自己的 GitLab CI/CD,一個 repo 每次產生一組 pipeline 裏面帶有多個 jobs,如下圖:

那如果需要在 A repo 的 pipeline 通知 repo B 一起進行編譯,並把 repo B 的 artifact 放進 A repo 的 artifact 時,我們能怎麽做?

option 1: 把 repo B 加入 repo A 的 sub module 一起編譯

option 2: 利用 GitLab 的 multiple-project pipeline 機制觸發另一個 pipeline

本篇將介紹 option 2 的 multiple-project pipeline 機制。

 

基本介紹 multiple-project pipeline

GitLab CI/CD 支援跨 project 的特性,由一個 pipeline 觸發另一個 pipeline。

觸發者被稱爲 upstream,接受被觸發的稱爲 downstream (它可以多個)。

如何觸發另一個 repo 的 pipeline 呢?

stages:
  - trigger_repob
  - buildTrigger-Repo-B:
 
stage: trigger_repob
  variables:
    ENVIRONMENT: staging
  trigger: 
    project: my_group/repoB
    branc: dev
    strategy: dependBuild-Repo-A:
  stage: build
  script:
    - echo "upstream"

關鍵字:trigger,它可指定變數從到 downstream,或是要觸發的 project 與 branch,以及是否要等待 pipeline 執行狀態再接著往下。

trigger 下可以用的 keywords 可以參考 Trigger job configuration keywords

觸發其他 project 的 pipeline 的畫面如下,可以看到 Downstream 可有多個,而且各自 Downstream 的 pipeline 可同時進行:

更多詳細的介紹請參考 Multiple-project pipelines

取得 Downstream 的 artifact

熟悉 Multiple-project pipelines 後,接下來是重點,我怎麽能從 upstream 取得 downstream 裏面 Job 的 artifact 呢?

從 GitLab issues 可以找到很多人許願這樣的功能:Allow job in upstream pipeline to reference artifacts from a downstream pipeline,但目前還沒有被支援,不過這篇裏面有人介紹了 workaround 做法,我們來看看吧。

以下 GitLab API 是我們下手的機會:

API 的使用流程(記得要申請 GitLab API Token)如下:

使用 API 的流程,我不建議寫在 .gitlab-ci.yml,因爲非常難 debug,因此,如果您是熟悉 shell 或 powershell 的人可以直接包裝成執行檔來進行。

以下是我用 powershell 寫的範例(rebuild.ps1: 假設 repoB 有一個 job: build-repo 是我想要的 artifact):

# use Bridge API to get downstream project id
$BRIDGE_API = "$CI_API/$PROJECT_ID/pipelines/$PIPELINE_ID/bridges"
$response = Invoke-RestMethod -URI $BRIDGE_API -HEADERS @{'PRIVATE-TKEN' = $TOKEN }
$downstream_project_id = $response.downstream_pipleline.project_id

# use Job API to get job content by downstream pipeline id
$JOB_API = "$CI_API/$downstream_project_id/pipelines/jobs"
$response = Invoke-RestMethod -URI $JOB_API -HEADERS @{'PRIVATE-TKEN' = $TOKEN }

# find target job to get id and artifact
$job_id = ""
$artifact = ""foreach ($job in $response) {
  if ($job.name -eq "build-repo") {
     $artifact = $job.artifacts_file
     $job_id = $job.id  }
}

# download artifact
$ARTIFACTS_API = "$CI_API/$downstream_project_id/jobs/$job_id/artifacts"
Invoke-RestMethod -URI $ARTIFACTS_API -HEADERS @{'PRIVATE-TKEN' = $TOKEN } -OutFile "./$($artifact.filename)"

最終合并到 .gitlab-ci.yml 的内容如下:

stages:
  - build
  - deploybuild-sharecode:
  
stage: build
  trigger:
    project: poulin/shopping-radar-sharecode
    branch: master
    strategy: depend
    
deploy-linbot:
  stage: delpoy
  script:
    - echo "start build"
    - powershell "./rebuild.ps1" "$CI_API_V4_URL/projects" $CI_PROJECT_ID $CI_PIPELINE_ID $env:GITLAB_TOKEN
    - cp ./sharecode ./bin
  needs:
    - build-sharecode
  only:
    - master
  tags:
    - windows

做法確實很 workaround,但很實用。上面的範例是針對 downstream 下的其中一個 job,如果您有多個 job 的 artifacts 要存取也可以修改裏面的程式碼進行使用哦。

References