【2022鐵人賽】使用Task與CLI的抉擇

這篇要來聊聊Azure DevOps Pipeline的Task與CLI的抉擇,為什麼會這樣說呢?

因為其實在Azure DevOps Pipeline中已經有提供許多不錯的Task設計,尤其.Net的程式在Azure DevOps Pipeline中有各式各樣對應的Task可以使用,像去年的文章「CI/CD從這裡:設定第一個Pipeline(範本與編輯介面介紹)」裡面就是使用內建的VSBuild Task來編譯.Net的程式碼,但是今年卻在「基本版-建立CI Pipeline(1)」文章內一開始就使用.Net Sdk的Container來編譯.Net的程式碼…

除了今年的文章屬於進階應用之外,還有其它幾個不同的因素考量:

  • Task要透過GUI才能快速方便知道有什麼參數可以選擇與設定
  • 不同功能可能要選用不同task
  • 可以達到相同功能的Task可能不只一個
  • 想要測試看看執行結果如何無法在Pipeline以外的環境執行
  • 用Container或直接用Sdk CLI可以在本機執行看看結果
  • 新功能或指令在Task可能沒有設計或支援
  • 如果是自管的Agent只要裝了Docker就可以

因為透過CLI就是組Scripts來達成目的,所以彈性相對高很多。例如.Net Core Sdk CLI除了可以Build Source Code之外,要Pack Nuget Package也是同樣透過Sdk CLI就可以達成,只是指令的組成不太一樣。但是如果是用Task的話,就會需要分成Nuget Task與.Net Core Task,或是pack也用.Net Core Task而不是用Nuget Task。

另外還有像是我們使用Azure DevOps Artifacts功能來存放私有的Nuget Packages,不過要Push上去是需要身份驗證授權的,在Task的選擇部份就有Nuget authenticate Task(搭配設定Service Connection),或是有個nuget.config檔案,裡面寫入PAT然後放在特定的位置來自動解決身份驗證的問題。

所以原本的dotnet-build-in-linux-container.yaml就可以重新做一份step template:

# steps/dotnet-sdk-in-linux-container.yaml

parameters:
  - name: dotnetSdkImgRepository
    type: string
    default: mcr.microsoft.com/dotnet/sdk:6.0-alpine
  - name: srcPath
    type: string
  - name: outputPath
    type: string
    default: $(Build.ArtifactStagingDirectory)/outputFiles/
  - name: slnOrCsprojName
    type: string
    default: Pipeline.sln
  - name: dotnetCommand
    type: string
  - name: dotnetCommandArgs
    type: string

steps:
  - script: |    
      echo "Dotnet sdk in linux container template"
      echo "${{ convertToJson(parameters) }}"
    displayName: Print template parameters
  - task: Bash@3
    displayName: Run dotnet sdk command in container
    inputs:
      targetType: 'inline'
      script: |
        if [ -d ${{ parameters.outputPath }} ]; then echo "${{ parameters.outputPath }} exist"; else mkdir -p ${{ parameters.outputPath }}; fi
        export UID=$(id -u)
        export GID=$(id -g)
        docker run --user $UID:$GID --rm \
        -v ${{ parameters.srcPath }}:/tmp/source \
        -v ${{ parameters.outputPath }}:/tmp/publish \
        -e DOTNET_CLI_HOME=/tmp/.dotnet \
        ${{ parameters.dotnetSdkImgRepository }} \
        dotnet ${{ parameters.dotnetCommand }} /tmp/source/${{ parameters.slnOrCsprojName }} \
        -o /tmp/publish ${{ parameters.dotnetCommandArgs }} \
  - task: ArchiveFiles@2
    displayName: 壓縮成zip
    inputs:
      rootFolderOrFile: $(Build.BinariesDirectory)
      includeRootFolder: false
      archiveType: 'zip'
      archiveFile: '$(Build.ArtifactStagingDirectory)/zipFiles/buildResult.zip'
      replaceExistingArchive: true

這樣就可以用同樣的一個範本搞定Build Source Code、Pack Nuget Package之類的事情,對應在jobs/buildCode.yaml就是把引用的template檔案改成新的,然後加上dotnetCommand、dotnetCommandArgs參數的設定就行了。

      - template: ../steps/dotnet-sdk-in-linux-container.yaml
        parameters:
          srcPath: ${{ parameters.sourcePath }}
          slnOrCsprojName: ${{ parameters.slnOrCsprojName }}
          dotnetCommand: publish
          dotnetCommandArgs: '-c ${{ parameters.buildConfiguration }}'

發佈留言