這篇要來聊聊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 }}'