關於 web service, unity, blogger 等軟體工程筆記

Continuous Integration With Unity (Auto builder) Using Jenkins

Edit icon 沒有留言
Continuous Integration With Unity (Auto builder) Using Jenkins

最近 Unity 專案開發,每次需要建置並部署 WebGL 到網頁伺服器,都需要大量時間等待,在兩三天就需要建置一個版本時,是一件很非常繁瑣的工作。因此在想這件事情能不能自動化,所謂的自動建置伺服器 (Auto builder),能在指定時間從 Git server 抓取最新的程式碼,呼叫 Unity Editor 建置新的 WebGL 版本,最後再將成品打包,然後發布到網頁伺服器上。

原本想說從 Git hook 著手自己重頭開始弄,再找著找著資料,發現這件工作,自動建置是軟體工程中的持續整合 (Continuous Integration, CI) 這一塊要解決的目標之一,又看了看網路上對於 CI 的解決方案,最後使用 Jenkins 這一套 Open source 軟體,來完成每日自動建置的工作。以下是實際建置該系統的筆記。

Jenkins Environment

在開始之前,先確保以下前置環境已經安裝並能夠運作:

首先從 Jenkins 官方網站下載最新版本並安裝,或是下載 Jenkins Window Installer。注意:Jenkins 需要 Java,請記得安裝 Java。待安裝完成後,先測試使用瀏覽器進入管理頁,預設是 http://127.0.0.1:8080/ 或是 http://localhost:8080/。

Welcome page in jenkins

進入「管理 Jenkins (Manage Jenkins)」,開啟「管理外掛程式 (Manage Plugins)」 頁面,安裝所需要的 Plugins,分別是 Git Plugin 負責從 Git server 更新程式碼,以及 Unity3dBuilder 呼叫 Unity Editor 來建置專案。

After installing plugins in jenkins

接著回到「管理 Jenkins (Manage Jenkins)」,開啟「設定系統 (Configure System)」,主要要設定 Unity3d 的安裝目錄,沒有這個步驟是找不到 Unity Editor 位置的。

unity3d settings in jenkins

Unity Editor Builder

在建立 Jenkins 建置任務前,我們得先在 Unity 專案中新增一組建置專案的程序 (Procedure),建立 Builder.cs,貼上以下範例程式碼,再根據需求修改:

using System;
using System.Linq;
using UnityEditor;

static class Builder
{
[MenuItem("Auto Builder/Build WebGL")]
public static void PerformBuildWebGL()
{
var path = string.Format("Builds/WebGL/{0:yyyy-MM-dd-hh-mm-ss}", DateTime.Now);

if (UnityEditorInternal.InternalEditorUtility.inBatchMode)
{
path = GetBatchModeBuildPath();

if (path == null)
{
throw new ArgumentException("-output is not set");
}
}

PerformBuildAuto(path, BuildTarget.WebGL);
}

static void PerformBuildAuto(string path, BuildTarget target)
{
var scenes = EditorBuildSettings.scenes.Where((v) => { return v.enabled; }).Select((v) => { return v.path; });
BuildPipeline.BuildPlayer(scenes.ToArray(), path, target, BuildOptions.None);
}

static string GetBatchModeBuildPath()
{
var args = Environment.GetCommandLineArgs();
for (int ii = 0; ii < args.Length; ++ii)
{
if (args[ii].ToLower() == "-output")
{
if (ii + 1 < args.Length)
{
return args[ii + 1];
}
}
}

return null;
}
}

注意以上程序在 Batch mode 需要額外參數,-output,指定建置結果資料夾位置。接著測試該 Builder 是否能建置完成,並且結果能夠正常執行。

Jenkins Job

前置作業終於準備完成,Jenkins 已經設定完成,Unity Editor Builder 也準備好。接著在 Jenkins 中「新增作業」,選擇「建置 Free-Style 軟體專案」模式。開始設定作業參數。以下提及以及重要設定。

原始碼管理 (Source Code Management)

選擇原始碼管理的方法,SVN 或是 Git,並輸入原始碼的 Repository 位置。

實務上 SSH 通訊連線到工作的 Git Server,Credentials 使用 SSH Username with private key 來認證。不使用 https 的原因是工作的 Server 是自我簽署 (self-signed certificate) 不被信任的憑證,因為要迴避這憑證檢查似乎還要做很多工,所以改用 SSH。Credentials 則是因為使用 Username with password 一直連不到,直到改用 SSH Key 後才能正常連線。

建置觸發程序 (Build Triggers)

選擇定期建置,輸入「00 06 * * *」設定為每日早上六點執行該作業。排程格式如下,更多細節可以參考 Corn expression 或是 Jenkins 官方文件

  1. MINUTES:分,使用 0-59
  2. HOURS:時,使用 0-23
  3. DAYMONTH,日,一個月的第幾天,使用 1-31
  4. MONTH,月,使用 1-12
  5. DAYWEEK,星期幾,一週的第幾天,使用 0-7,0 和 7 表示星期日
  • *:表示所有合法數值
  • M-N:表示數值區間
  • M-N/X or */X:表示在合法數值區間中,間隔 X 數值
  • A,B,...,Z:表示數值列舉

若想要每五分鐘執行,「*/5 * * * *」。若想要星期一以及星期三早上八點執行,「0 8 * * 1,3」。若想要每天上午八點到下午六點每兩個小時執行,「0 8-18/2 * * *」。

建置 (Build)

「新增建置步驟 (Add build step)」,選擇「Invoke Unity3d Editor」,選擇環境設定中所新增的 Unity Editor 組態,Command line Arguments 輸入:

-logFile "$WORKSPACE/unity3d_editor.log" -quit -batchmode -nographics -executeMethod Builder.PerformBuildWebGL -output /Builds/

其中說明幾項參數:-logFile 記錄 Unity Editor log。executeMethod 表示要呼叫哪一個靜態程序 (Static procedure),可以參考前章節所提供的範例程式碼。-output 為範例程式碼所需,表示建置輸出資料夾位置。

更多關於 Unity 參數說明可以參考官方文件 Command line arguments

建置後動作 (Post-build Actions)

新增動作「封存成品 Archive the artifacts」。對於 Unity WebGL 建置結果,「封存檔案 Files to archive」設定為 /Builds/**/*.*,便可正確封存 Unity WebGL 建置的結果。

Test

進入該作業資訊頁中,立刻按下「立即建置 (Build Now)」,追蹤該項建置的「Console output」看看是否運作正常。順利建置完成的話,應該可以看到該次建置結果的封存檔案。由於 Unity WebGL 建置結果是網頁形式,可以在 Jenkins 建置成功結果頁,直接點選 index.html 直接開啟瀏覽。

View build result in jenkins

瀏覽器應該會是沒有什麼反應,無法正常執行,並且提示錯誤,Blocked script execution。這是由於 Jenkins 安全機制設定,建置結果網頁的標頭設定 (Headers),Content-Security-Policy,會使得讓瀏覽器遵循,不允許執行該網頁的 JavaScript。要能夠正常瀏覽網頁,處理方案最好是新增另一個建置後動作,將該次建置結果發佈到其他的網頁伺服器。或是實務環境可以不管安全性,索性關閉 Jenkins 安全機制,讓瀏覽器能執行 JavaScript,以正常瀏覽該網頁。

關閉安全機制的方法很簡單,開啟「管理 Jenkins (Manage Jenkins)」「Jenkins 命令列介面 (Script Console)」,輸入下面指令即可:

System.clearProperty("hudson.model.DirectoryBrowserSupport.CSP")

更多關於安全性細節說明,可參考官方文件 Configuring Content Security Policy

Finally...

終於設定完一個簡易的 CI Job,每日會自動建立一個新版本,並可以隨時隨地上 Jenkins 頁面追蹤並展示成果。之後還需加上其它的功能整合,例如自動測試 單元測試,寄送建置結果郵件,建置錯誤處理,將建置結果訊息送上 Slack 等等…。

Reference

沒有留言: