【2022鐵人賽】取得目前的Git Commit SHA

前一篇幾乎已經將流程規劃說明裡面規劃的CI Pipeline做完了,準備進入到CD Pipeline的時候發現在前面的某一個環節漏掉了一個滿重要的部份,那就是取得當時觸發Pipeline的Git Commit SHA記錄,就是該次CI Pipeline取得來源的基準,這個資訊會在後面的CD Pipeline使用到,因為我們要透過它執行Tag、建立PR來Merge到Release branch。

我們要取得的是程式Source code存放的Git Repo內的記錄,所以這個動作是加在BuildCode的Job裡面,至於加在編譯之前或之後都沒影響,只要放在checkout: sources之後就Ok,取得的Git Commit SHA會存成文字檔,然後放到Pipeline Artifacts裡面不同的目錄。

      - task: Bash@3
        displayName: Check folder exist or create
        inputs:
          targetType: 'inline'
          script: |
            if [ -d "$(Build.ArtifactStagingDirectory)/pipelineFiles/" ]; then echo "$(Build.ArtifactStagingDirectory)/pipelineFiles/ exist"; else mkdir -p "$(Build.ArtifactStagingDirectory)/pipelineFiles/"; fi
      - task: PowerShell@2
        displayName: 'Get git commit sha'
        inputs:
          targetType: 'inline'
          workingDirectory: $(Build.SourcesDirectory)
          pwsh: true
          script: |
            $gitFullCommitSHA = git rev-parse HEAD
            $gitCommitSHA = $gitFullCommitSHA.Substring(0,8)

            echo "git commit sha: $gitCommitSHA"
            echo "git full commit sha: $gitFullCommitSHA"

            echo "$gitFullCommitSHA" > $(Build.ArtifactStagingDirectory)/pipelineFiles/gitCommitSHA.txt
      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)/pipelineFiles'
          ArtifactName: 'PipelineFiles'
          publishLocation: 'Container'

上面的這三個Task就是負責取得Git Commit SHA並存成文字檔後上傳到Pipeline Artifacts並放在PipelineFiles目錄底下。

第一個Task是確認pipelineFiles目錄是否存在,不存在就建立它,不然我們要放文字檔的目錄不存在會有Error。

第二個Task則是利用PowerShell Core(pwsh: true,這樣才能跨平台使用)執行git指令來取得Commit SHA資訊。因為PowerShell可以方便使用Substring取得前8碼的文字,不然使用Bash也可以。取得的內容透過echo輸出到Log內容上面方便有問題查閱,另外再輸出到txt文字檔。

第三個Task就是把文字檔放到Pipeline Artifacts裡面,這樣後續的CD Pipeline才方便取得這個檔案。

最後全部的YAML內容應該是下面這些:

trigger:
- none

pool:
  vmImage: ubuntu-latest

resources:
  repositories:
  - repository: sources
    type: git
    name: ironman2022/NetApp
    ref: Develop
    trigger:
      branches:
        include:
          - Develop

variables:
  pipelineArtifact: output
  buildResultZipName: buildResult.zip
  slnOrCsprojName: IronmanWeb.sln
  imgRepository: 'asia-east1-docker.pkg.dev/feisty-mechanic-363012/ironman2022/ironmanweb'
  buildDockerfile: 'Dockerfile'
  imgRegistryService: 'GCPArtifactRegistry'
  cloudRunServiceName: ironmanweb
  cloudRunPort: 8080
  cloudRunRegion: asia-east1
  cloudRunProjectId: feisty-mechanic-363012
  gcpAuthJsonFile: ironman2022-gcp-key.json

jobs:
  - job: BuildCode
    steps:
      - checkout: sources
        clean: true
      - task: Bash@3
        displayName: Check folder exist or create
        inputs:
          targetType: 'inline'
          script: |
            if [ -d "$(Build.ArtifactStagingDirectory)/pipelineFiles/" ]; then echo "$(Build.ArtifactStagingDirectory)/pipelineFiles/ exist"; else mkdir -p "$(Build.ArtifactStagingDirectory)/pipelineFiles/"; fi
      - task: PowerShell@2
        displayName: 'Get git commit sha'
        inputs:
          targetType: 'inline'
          workingDirectory: $(Build.SourcesDirectory)
          pwsh: true
          script: |
            $gitFullCommitSHA = git rev-parse HEAD
            $gitCommitSHA = $gitFullCommitSHA.Substring(0,8)

            echo "git commit sha: $gitCommitSHA"
            echo "git full commit sha: $gitFullCommitSHA"

            echo "$gitFullCommitSHA" > $(Build.ArtifactStagingDirectory)/pipelineFiles/gitCommitSHA.txt
      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)/pipelineFiles'
          ArtifactName: 'PipelineFiles'
          publishLocation: 'Container'
      - script: |
          export UID=$(id -u)
          export GID=$(id -g)
          docker run --user $UID:$GID --rm \
          -v $(Build.SourcesDirectory):/tmp/source \
          -v $(Build.BinariesDirectory):/tmp/publish \
          -e DOTNET_CLI_HOME=/tmp/.dotnet \
          mcr.microsoft.com/dotnet/sdk:6.0-alpine \
          dotnet publish /tmp/source/$(slnOrCsprojName) \
          -c release \
          -o /tmp/publish
        displayName: Dotnet Build
      - task: ArchiveFiles@2
        displayName: 壓縮成zip
        inputs:
          rootFolderOrFile: $(Build.BinariesDirectory)
          includeRootFolder: false
          archiveType: 'zip'
          archiveFile: '$(Build.ArtifactStagingDirectory)/zipFiles/$(buildResultZipName)'
          replaceExistingArchive: true
      - task: PublishBuildArtifacts@1
        displayName: 上傳到Pipeline Artifact
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)/zipFiles/$(buildResultZipName)'
          ArtifactName: '$(pipelineArtifact)'
          publishLocation: 'Container'
  - job: BuildImage
    dependsOn: BuildCode
    steps:
      - task: DownloadBuildArtifacts@0
        displayName: 下載Pipeline Artifact
        inputs:
          buildType: 'current'
          cleanDestinationFolder: true
          downloadType: 'single'
          artifactName: '$(pipelineArtifact)'
          downloadPath: '$(System.ArtifactsDirectory)/'
      - task: ExtractFiles@1
        displayName: Unzip zip
        inputs:
          archiveFilePatterns: '$(System.ArtifactsDirectory)/$(pipelineArtifact)/$(buildResultZipName)'
          destinationFolder: '$(System.ArtifactsDirectory)/BuildImage'
          cleanDestinationFolder: true
          overwriteExistingFiles: true
      - task: Docker@2
        displayName: Build image
        inputs:
          repository: '$(imgRepository)'
          command: 'build'
          Dockerfile: $(buildDockerfile)
          buildContext: '$(System.ArtifactsDirectory)/BuildImage'
          arguments: '--no-cache'
          tags: |
            latest
      - task: Docker@2
        displayName: "Login to Container Registry"
        inputs:
          command: login
          containerRegistry: $(imgRegistryService)
      - task: Bash@3
        displayName: Push docker image
        inputs:
          targetType: 'inline'
          script: |
            docker push -a $(imgRepository)
  - job: DeployCloudRun
    dependsOn: BuildImage
    steps:
      - task: Bash@3
        displayName: Deploy docker image to cloudrun
        inputs:
          targetType: 'inline'
          script: |
            docker run --rm \
            -v $(Build.SourcesDirectory)/$(gcpAuthJsonFile):/gcp/cloudKey.json \
            asia.gcr.io/google.com/cloudsdktool/google-cloud-cli:latest \
            bash -c "gcloud auth login --cred-file=/gcp/cloudKey.json && gcloud run deploy $(cloudRunServiceName) --set-env-vars=Ironman=$(Build.BuildId) --image $(imgRepository) --region $(cloudRunRegion) --project $(cloudRunProjectId) --allow-unauthenticated"

順便貼上整個CI Pipeline執行結果的畫面,除了手動觸發Pipeline執行之外,也可以從Develop建立子分支,加個檔案或是修改文字內容之後建立PR試跑整個流程看看。

Log中查看Commit SHA
上傳到Pipeline Artifacts的文字檔
明細頁的路徑/資訊對照

補完這個項目,下一篇就可以進入CD Pipeline(Release)的設計了。

發佈留言