4

在 Azure Pipelines 裡面正確使用 ROBOCOPY 複製檔案的方法

 3 years ago
source link: https://blog.miniasp.com/post/2021/07/23/Properly-Use-Robocopy-Exit-Codes-in-Azure-Pipelines
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在命令列環境下執行程式,這個世界普遍有個共識,那就是應用程式的結束狀態碼(Exit Code)為 0 時,就會被視為是「沒有錯誤」的結果。任何非 0 的結束狀態碼,都代表有一定程度的錯誤發生。因此在 Azure Pipelines 或任何其他 CI 平台上,預設遇到應用程式回傳 Non-Zero 的結束狀態碼,就會自動報錯。誰知道 ROBOCOPY 原來複製成功,也會回傳非 0 的結束狀態碼!

原始的命令

以下就是我手動執行命令的腳本,測試過很多遍,是沒問題的:

$SourceRoot = 'D:\Projects\MyProject'
$TomcatAppPath = 'C:\Program Files\Apache Software Foundation\Tomcat 8.5\webapps'

ROBOCOPY /E "$SourceRoot\web\build\war-tmp"   "$TomcatAppPath\web" /NP /NFL /NDL /NJH /NJS

ROBOCOPY /E "$SourceRoot\api\build\war-tmp"   "$TomcatAppPath\api" /NP /NFL /NDL /NJH /NJS

修改過的命令

$SourceRoot = 'D:\Projects\MyProject'
$TomcatAppPath = 'C:\Program Files\Apache Software Foundation\Tomcat 8.5\webapps'

ROBOCOPY /E "$SourceRoot\web\build\war-tmp"   "$TomcatAppPath\web" /NP /NFL /NDL /NJH /NJS
if( $LASTEXITCODE -ge 8 ) {
    throw ("An error occured while copying to $TomcatAppPath\web. [RoboCopyCode: $($LASTEXITCODE)]")
} else {
    $global:LASTEXITCODE = 0;
}

ROBOCOPY /E "$SourceRoot\api\build\war-tmp"   "$TomcatAppPath\api" /NP /NFL /NDL /NJH /NJS
if( $LASTEXITCODE -ge 8 ) {
    throw ("An error occured while copying to $TomcatAppPath\api. [RoboCopyCode: $($LASTEXITCODE)]")
} else {
    $global:LASTEXITCODE = 0;
}

修改 Azure Pipelines 專用的命令

$SourceRoot = '$(Build.SourcesDirectory)'
$TomcatAppPath = '$(Build.ArtifactStagingDirectory)\Apache\Tomcat85\webapps'

ROBOCOPY /E "$SourceRoot\web\build\war-tmp"   "$TomcatAppPath\web" /NP /NFL /NDL /NJH /NJS
if( $LASTEXITCODE -ge 8 ) {
    throw ("An error occured while copying to $TomcatAppPath\web. [RoboCopyCode: $($LASTEXITCODE)]")
} else {
    $global:LASTEXITCODE = 0;
}

ROBOCOPY /E "$SourceRoot\api\build\war-tmp"   "$TomcatAppPath\api" /NP /NFL /NDL /NJH /NJS
if( $LASTEXITCODE -ge 8 ) {
    throw ("An error occured while copying to $TomcatAppPath\api. [RoboCopyCode: $($LASTEXITCODE)]")
} else {
    $global:LASTEXITCODE = 0;
}

為什麼不容易發現問題

我個人實作 Pipelines 的方式,都是先將所有步驟寫成指令碼,然後再搬移到 Pipelines 執行。如果你可以手動透過命令執行成功,那麼套用到 CI/CD 肯定也沒問題!

為什麼我會沒發現 ROBOCOPY 複製成功時並非回傳狀態碼 0 的結果呢?因為我是這樣做的:

  1. 先寫好指令,並手動測試個幾次
  2. 確認指令沒問題,確認回傳狀態碼為 0
  3. 設定 Azure Pipelines 並測試執行,得到回傳狀態碼為 1(見鬼啦~)
  4. 重新用手動執行,確認回傳狀態碼為 0
  5. 再測試一次 Pipeline 並得到回傳狀態碼為 1(見鬼啦~)
  6. 無限鬼打牆... ♾

這是因為我每次手動部署的時候,其實在 $(Build.ArtifactStagingDirectory) 目錄下都已經有檔案,而 ROBOCOPY 只有一種條件會回傳狀態碼 0,那就是 No errors occurred, and no copying was done. (沒有錯誤發生,且沒有檔案被複製)。但是 Azure Pipelines 被觸發執行的時候,會清除所有 $(Build.ArtifactStagingDirectory) 目錄下的內容,這才發生這種鬼打牆的事件!

深入 ROBOCOPY 結束狀態碼

深入瞭解之後我才發現,原來 ROBOCOPY 的結束狀態碼只要是 0 ~ 7 都屬於正常結束,大於等於 8 的結束狀態碼才是有問題的。

ROBOCOPY 的狀態碼比一般命令列程式還複雜許多,他使用 bitmap 或稱 flags 來代表多種狀態的組合,基本的 flag 有以下這些,可以自由組合:

  • 結束狀態碼 0 代表的意義是
    • No errors occurred, and no copying was done. The source and destination directory trees are completely synchronized.
  • 結束狀態碼 1 代表的意義是
    • One or more files were copied successfully. (that is, new files have arrived).
  • 結束狀態碼 2 代表的意義是
    • Some Extra files or directories were detected. No files were copied. Examine the output log for details.
  • 結束狀態碼 4 代表的意義是
    • Some Mismatched files or directories were detected. Examine the output log. Housekeeping might be required.
  • 結束狀態碼 8 代表的意義是
    • Some files or directories could not be copied. (copy errors occurred and the retry limit was exceeded). Check these errors further.
  • 結束狀態碼 16 代表的意義是
    • Serious error. Robocopy did not copy any files. Either a usage error or an error due to insufficient access privileges on the source or destination directories.

我曾經聽到在網路上有人說過:「不要跟我談什麼 CI/CD,你先手動執行個 100 遍再來跟我說話。」

以往各種人工作業,大家會在無數次試誤(try and error)的過程中,流失掉許多寶貴的經驗與知識,以致於錯誤不斷再犯,無法建立起十足的信心自動化。但是導入自動化建置與部署的過程中,由於把所有過程指令化,達到 IaC (Infrastructure as Code) 的效果,讓你可以對這些腳本進行版控,累積起大大小小的經驗,就算有錯誤,修掉之後也會不斷累積自信,讓公司的自動化越做越好。

沒有累積夠多的人工建置與部署經驗,在實現 CI/CD 的過程中,會遭遇到你想像不到的各種狀況。這些年許多客戶找我們幫忙建置 CI/CD 環境,客戶雖然不擅長自動化的過程,但是我們會在導入的過程中,幫助客戶釐清各種問題,過程中不但可以發現問題,還可以開始改變觀念。

一般公司大多只想直接購買解決方案來快速解決問題,但事實上,自動化的過程其實是在累積公司資產,把各種無形的知識,透過指令碼(Code)的方式,累積成公司長久可維護的有形知識。過程中會遇到許多挑戰,把冰山下方的所有問題一一浮現,同時也能讓公司的體質變的越來越好!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK