Azure DevOps in Action - 建立你的第一個Build Pipeline
當開始邁向CI(continuous integration),我們第一個要實現的任務是,以雲端(伺服器端)的環境為準,來進行系統的開發、建置、佈署、與測試。
在過去(仿佛是上個世紀以前了),開發人員可能是以某一台個人開發環境的電腦為準,在多人開發協作之後,把程式碼集中在這台電腦上,進行最終的建置與測試。
但當我們導入了版控系統(像是Git)之後,即便多人同時開發、修改、增添新功能,甚至嘗試一些特殊調整。但在伺服器端,應該總是保持著一套最穩定的版本,可能是Master分支、或是Release分支(選擇分支的策略由團隊決定),這是之前我們討論版控時候的最終目標與CI的基礎。
當有了這個基礎之後,我們可以建立一個自動化建置的流程,一般稱之為CI Pipeline。由於使用不同的開發語言(或框架),可能會有著不同的建置流程,因此我們接著會逐步來看,在不同的開發技術下,CI Pepiline的設計方式。
建立 .net framework 專案的Build Pipeline
我們先來看基本的 .net framework專案,如果要練習,你可以建立一個新的Azure DevOps專案,並且在Repos處Clone/Import我們底下這個在GitHub上的程式碼。
這是筆者在github上的範例,是一個傳統的 .net framework MVC Web專案(後面我們會在介紹 .net core的做法),功能是實現一個計算BMI的Web應用程式。
你可以使用Azure DevOps Repos起始畫面的import功能,匯入這個GitHub上的Repo:
一陣忙碌:
完成後,你會看到類似底下這樣的程式碼:
有了source code在Repos中,接著,我們就可以來試試看建立Build Pipeline了。
請點選Azure DevOps左方主選單的Pipelines a New Pipeline:
在緊接著出現的畫面中(下圖),選擇最下方的『Classic Editor』。
下圖中上面的幾個選項是透過撰寫YAML Code的方式來設計Pipeline,而我們先選用GUI(Classic Editor):
由於我們的source code已經存放在預設的Azure Repo中(就是你剛才import進來的那份),且位於master主幹上,因此我們直接選擇預設的選項後,點選『continue』即可:
在接下來出現的畫面中,我們選擇 ASP.NET,按下Apply:
按下之後,你會發現系統自動帶出ASP.NET適用的Piepline模板:
上圖左方框起來的是Pipeline中的Tasks(自動化建置步驟),你完全無需修改,直接儲存順便跑一個建置動作(Save & queue)即可:
在出現的畫面上(上圖),按下『Save and run』。系統就開始雲端建置工作了:
上圖A中的Agent job1,就是正在雲端跑的自動化建置工作,你可以點進去,會看到運行的即時狀態:
上圖左方的A,是正在跑的Task,右方B的部分則是運行中的console顯示。如果你依照我們前面的說明一步一步做下來,沒一會兒可能會很訝異的看到底下這個錯誤畫面:
別怕,這是我們刻意的。
請注意,發生錯誤的位置是『Test Assemblies』這個Task,如果你對照前面的Editor畫面,就是底下這顆:
這顆Task是負責運行專案中的Unit Test的,我們曾經說過,近代軟體開發中,很倚賴Unit Test這樣的機制作為程式碼的把關。
Unit Test稱作單元測試,我們可以透過撰寫測試程式碼,以自動化的方式來測試主程式。這帶來了許多好處,可以大幅度的提高程式碼的品質,且減少回歸測試的工作量。
上面的Pipeline就是因為單元測試失敗,導致整個建置動作失敗。我們可以把這個專案透過Visual Studio 2019 Clone下來,並開啟。
然後接著以手動的方式Build整個方案:
你會發現,當你嘗試Build這個方案,他是可以正確地被建置的。
這表示這些專案沒有任何語法上的錯誤。然而,當你執行這個專案的程式時,它運算BMI的結果卻是錯誤的:
BMI是體重除以身高的平方,體重是以公斤為單位,身高是公尺。因此,上述計算正確的結果應該是24.22:
70/(1.7x1.7)=24.22
但我們的程式卻顯示為『70』。
這個錯誤源自於底下這段計算BMI的核心程式碼:
public float Calculate()
{
float result = 0;
//發生錯誤的位置
float height = (int)Height / 100;
result = Weight / (height * height);
return result;
}
上面程式碼其中的
float height = (int)Height / 100;
造成了錯誤,(int)這樣的型別轉換導致計算結果不正確,如果你修改成
float height = (float)Height / 100;
則運算就會成功。
然而,這個程式碼邏輯上的錯誤,對於Build來說,卻不會造成任何問題(因為沒有寫錯任何語法),但執行的結果卻是錯的。
重點在於,Pipeline中運作Unit Test的tasks,順利地為我們抓取並攔截下了這個錯誤(雖然Build的時候沒有任何的語法異常),但撰寫了Unit Test的程式,在面對這類邏輯性的錯誤上,將可以為我們的系統帶來更大的保障。一切的前提當然是我們在專案中已經先撰寫好Unit Test的code了,但在這邊我們在這邊先不談Unit Test的撰寫,我們先了解Unit Test可以為我們帶來這些好處(後面會再找時間介紹如何開發)。
而用戶端Visual Studio的Test Explorer工具,可以幫我們手動運行Unit Test(下圖中左上角的Play按鈕):
例如上圖A是手動執行該專案中Unit Test的結果。
一般來說,成熟的專案中可能會有幾十甚至數百個Unit Test,這些為數眾多的Unit Test當不然可能頻繁的在開發端手動逐一執行,而Azure DevOps的自動化建置中的『Test Assemblies』這個Task,會在Pipeline進行Build的過程中,幫我們運行Unit Test,以確保開發品質得以提升。
總的來說,我們可以在程式專案中,撰寫更多的Unit Test,透過這些Unit Test,可以在Pipeline被執行時,自動檢查程式碼的正確性,守護系統的品質。當然,你必須先有Unit Test的觀念,如果你不曾寫過,暫且不用擔心,後面我們會介紹。
但你應當開始發現CI Pipeline的種種好處了…除了自動建置、持續整合(多人開發時),自動建置時帶入Unit Test的執行,也是很重要的…
留言