2016年12月20日 星期二

[iThome第8屆鐵人賽 09]建制失敗的處理 - 為什麼失敗了但是build server還是認為成功

在進入下個階段之前(也就是開始執行Unit Test),有個部分一直沒有碰到,那就是當建制失敗的時候會發生什麼事情。

整個CI的概念就是盡早發現建制有問題好去做一些處理,但是如果出錯了都發現不到,不就等於沒有意義了?

這篇我們將會看看這方面的處理。

sample 程式在 github devops-psake sample/chapter9

當Build有錯會怎麼樣?

我們首先來看看,當我們故意修改程式碼,讓他build不下去,會出現什麼內容。

image
從圖片可以看到,雖然MSBuild說失敗了,但是psake還是認為成功了

這會有什麼問題?

最大的問題會在,當我們要結合一些Build Server的時候,因為他呼叫的是psake,而psake告訴他成功(雖然MSBuild告訴他失敗),所以build server就認為成功。

換句話說,就算失敗了我們也永遠不會知道

等於是整個建制scrip更本沒辦法使用了。

問題原因分析

這個問題,其實很簡單,有點像是程式裡面,如果出現了Exception,把它Tray catch不做任何事情是一樣的概念,當MSBuild出錯的時候,我們的psake就像是掩耳盜鈴一樣,管他是不是跑成功了, 他永遠回傳成功。

所以,我們要面對現實,當建制失敗了,這個資訊要傳出去。

但是另外一個問題來了,我們怎麼知道MSBuild建制失敗了?

任何一個console程式,其實都有一個Exit Code的概念,就是當他執行完,他會回傳一個值,如果 = 0,表示沒有問題,不是0表示有問題。(話說,我寫console都沒有照這個原則)

解決方式 - exec

既然知道有exit code之後,我們可以讓psake檢查,如果是0,就表示沒問題,是0以外表示有問題,就拋出exception。

可以想象當我們要呼叫的程式越來越多,每一個都要加上這個判斷真的不方便,所以psake提供了一個exec的方法,專門幫忙做上面的判斷。

所以,我們調整 task Compile變成:

task Compile -depends Clean, Init -description "編譯程式碼" `
    -requiredVariables solutionFile, buildConfiguration, buildTarget, buildTempDirectory `
{ 
 Write-Host "開始建制檔案:$solutionFile"

 $buildParam = "Configuration=$buildConfiguration" +
     ";Platform=$buildTarget" + 
     ";OutDir=$buildTempDirectory"
 
 $buildParam = $buildParam + ";GenerateProjectSpecificOutputFolder=true"

 exec {msbuild $solutionFile "/p:$buildParam"}
} 
 
image
psake 會報錯了
未來執行外部程式一定要記得呼叫exec包住

還有一道步奏

最後,就算是這樣,我們build server還是不認為失敗,原因很簡單,同樣概念,builder server呼叫的是 build.ps1,可是報錯的是default.ps1,如果錯誤訊息沒有往上傳,build server還是認為成功。

因此,我們要在build.ps1,把這個錯誤訊息往上傳:

...

Write-Host "建制的Exit Code:$LastExitCode"

# 把錯誤碼往上傳
exit $LastExitCode 
 

$LastExitCode是powershell裡面記錄最後一個執行完回傳的結果,所以我們可以用這個值來呈現到我們build結果

結語

在這篇我們了解到psake怎麼和其他console程式做結合,並且了解透過exit code的方式來知道是否執行成功。

因此,下次在寫console程式的時候,別忘記最後都回傳一個exit code,未來如果自己程式要和這種build結合才有辦法達到

下篇,我們正式進入另外一個部分,程式不是build起來就好了,還要確認所有檢查要通過,而這個檢查就是單元測試。

沒有留言 :

張貼留言