前一篇幾乎已經將流程規劃說明裡面規劃的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試跑整個流程看看。
補完這個項目,下一篇就可以進入CD Pipeline(Release)的設計了。