這篇文章會要介紹一個 .NET 平台的建置工具:FlubuCore。(最後更新日期:2022-2-5)
內容大綱:
👉本文範例適用 FlubuCore v6.3.0 或更新的版本。
安裝完成後,將來便可以利用命令列工具 flubu 來建置專案。
要提醒的是,如果你原本已經在建置腳本專案中使用了 FlubuCore,後來要更新到最新的版本,那麼除了更新專案中的 FlubuCore 套件,你還必須更新它的全域工具:
操作指引:在 Visual Studio 中開啟應用程式的方案(solution),然後在此方案中加入一個新專案。專案範本選擇 Class Library,參考下圖:
把目錄展開,會像這樣:
(root)
+ build
build.csproj
BuildScript.cs
+ source
- BuildAll.sln
+ MyApp
+ ClassLibrary1
+ doc
+ output
其中的 output 目錄是用來存放產品部署的檔案,無需事先建立。
另一種常見的配置是把建置腳本專案放在 source 目錄下,也是沒問題的,只要建置腳本在執行的時候能夠找到你的 solution 的 .sln 檔案就行了(底下範例有展示如何指定 .sln 檔案的所在路徑與檔名)。
Build script 專案建立完成後,把專案範本預設添加的 Class1.cs 檔案刪除,然後透過 Nuget 套件管理員加入 FlubuCore 套件:
👉 如果要安裝最新的預覽版,請將上圖中的 Include prerelease 選項打勾。
接著加入一個類別,命名為 "BuildScript.cs"。注意這裡的檔案名稱也是按照慣例來命名的,不要任意取別的名稱。
底下是一個典型的建置腳本:
此建置腳本具備三項任務(targets):
此範例的 ProductVersion.txt 只是單純的文字檔,裡面只有一行文字,寫著版本編號,例如 "3.1.0"。
另外,本文也有提到 Flubu 命令列工具能夠產生 .flubu 檔案,以便紀錄建置腳本檔案的所在路徑。這個 .flubu 檔案的內容雖然簡單(內容只有兩行文字),但是卻扮演了相當重要的角色,因為它解決了建置腳本的一個重要問題:如何決定工作目錄,以便在編寫建置腳本時能夠使用相對路徑名。有關這個部分,我會在下一篇文章裡進一步說明。
Happy building!
內容大綱:
- 簡介
- 安裝
- 加入 build script 專案
- 執行 build script
- 使用 .flubu 檔案
- 結語
簡介
FlubuCore 的意思是「Fluent Builder Core」。從名稱便可看出,它跟 Nuke 一樣是自動建置專案的工具、可使用流暢式(fluent)API 寫法、以及支援 .NET Core。雖然它也支援傳統的 .NET Framework,但我只在意 .NET Core,所以本文部分內容可能不適用於 .NET Framework。安裝
用以下指令來安裝 Flubu 的 .NET 全域工具:dotnet tool install --global FlubuCore.Tool
👉本文範例適用 FlubuCore v6.3.0 或更新的版本。
安裝完成後,將來便可以利用命令列工具 flubu 來建置專案。
要提醒的是,如果你原本已經在建置腳本專案中使用了 FlubuCore,後來要更新到最新的版本,那麼除了更新專案中的 FlubuCore 套件,你還必須更新它的全域工具:
dotnet tool update --global
FlubuCore.Tool
加入 build script 專案
FlubuCore 跟 Nuke 有個相同之處:它們的建置腳本就是我們平常在寫的 C# 程式。所以第一個步驟就是要在我們的應用程式的方案(solution)中加入一個新的專案,用來寫建置腳本。註:FlubuCore 有提供命令列工具來快速建立 build script 專案,只是我傾向手動建立,以便經歷每個細節。這個建置腳本的專案一般建議命名為 "build"、"Build" 或 "_Build" 或 "BuildScript",請不要使用其他不符合慣例的名稱,以免增加自己的麻煩。(flubu 命令列工具會自動搜尋幾個常用的資料夾名稱,稍後有完整列表。)
操作指引:在 Visual Studio 中開啟應用程式的方案(solution),然後在此方案中加入一個新專案。專案範本選擇 Class Library,參考下圖:
接著要替專案命名、指定專案存放的位置、以及指定目標框架(target framework)。
我通常給專案名稱取名為 "build",並將它存放於整個 repository 工作目錄的最上層,而目標框架則使用 .NET 5.0。
專案的目錄結構看起來會像這樣:
把目錄展開,會像這樣:
(root)
+ build
build.csproj
BuildScript.cs
+ source
- BuildAll.sln
+ MyApp
+ ClassLibrary1
+ doc
+ output
其中的 output 目錄是用來存放產品部署的檔案,無需事先建立。
另一種常見的配置是把建置腳本專案放在 source 目錄下,也是沒問題的,只要建置腳本在執行的時候能夠找到你的 solution 的 .sln 檔案就行了(底下範例有展示如何指定 .sln 檔案的所在路徑與檔名)。
Build script 專案建立完成後,把專案範本預設添加的 Class1.cs 檔案刪除,然後透過 Nuget 套件管理員加入 FlubuCore 套件:
👉 如果要安裝最新的預覽版,請將上圖中的 Include prerelease 選項打勾。
接著加入一個類別,命名為 "BuildScript.cs"。注意這裡的檔案名稱也是按照慣例來命名的,不要任意取別的名稱。
底下是一個典型的建置腳本:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using FlubuCore.Context; | |
using FlubuCore.Context.Attributes.BuildProperties; | |
using FlubuCore.IO; | |
using FlubuCore.Scripting; | |
using FlubuCore.Tasks.Attributes; | |
using FlubuCore.Tasks.Versioning; | |
// 注意:需要 FlubuCore v5.1.8 或更新的版本。 | |
namespace _Build | |
{ | |
public class BuildScript : DefaultBuildScript | |
{ | |
// 指定建置結果的輸出目錄。 | |
public FullPath OutputDirectory => RootDirectory.CombineWith("output"); | |
[ProductId] | |
public string ProductId { get; set; } = "MyApp"; | |
// 指定 .sln 檔案。這裡加上了 "source/",是因為我把建置專案放在 repository 的跟目錄。 | |
[SolutionFileName] | |
public string SolutionFileName => RootDirectory.CombineWith("source/BuildAll.sln"); | |
[BuildConfiguration] | |
public string BuildConfiguration { get; set; } = "Release"; // Debug or Release | |
// 使用外部檔案來控制產品版本,檔案應放在 source 目錄下(跟 .sln 檔案同一層)。 | |
[FetchBuildVersionFromFile(ProjectVersionFileName = "ProductVersion.txt")] | |
public BuildVersion Version { get; set; } | |
protected override void ConfigureTargets(ITaskContext session) | |
{ | |
Console.WriteLine($"輸出目錄為 {OutputDirectory}"); | |
Console.WriteLine($"產品版本為 {Version}"); | |
var clean = session.CreateTarget("clean") | |
.SetDescription("Cleaning solution output folder.") | |
.AddCoreTask(x => x.Clean() | |
.CleanOutputDir()); | |
var compile = session.CreateTarget("compile") | |
.SetDescription("編譯整個 solution。") | |
.AddCoreTask(x => x.Build() | |
.Version(ProductVersion.Version.ToString())); | |
var publish = session.CreateTarget("publish") | |
.SetDescription("Publish binaries.") | |
.DependsOn(compile) | |
.AddCoreTask(x => x.Publish() | |
.OutputDirectory(OutputDirectory)); | |
} | |
} | |
} |
此建置腳本具備三項任務(targets):
clean
:清空輸出資料夾(第 36~39 行)。compile
:編譯整個 solution(第 41~44 行)。這裡還一併指定了應用程式的版本編號,而版本編號是由外部檔案 ProductVersion.txt 來控制。publish
:發佈(第 46~50 行)。發佈的時候,通常會指定一個輸出資料夾。
publish
依賴 compile
,而 compile
又依賴 clean
。所以當你在命令列指定要執行 publish
任務時,就會依序執行 clean
、compile
、和 publish
。補充說明:如果透過UpdateNetCoreVersionTask
方法來指定應用程式的版本編號,它會去修改專案的.csproj 檔案,並在其中加入<Version>
、<AssemblyVersion>
、<FileVersion>
等元素。
此範例的 ProductVersion.txt 只是單純的文字檔,裡面只有一行文字,寫著版本編號,例如 "3.1.0"。
👉 如果使用 MinVer 套件來控制版本編號,作法更簡單,只要把 MinVer 套件加入應用程式專案,然後在發布新版本時,用 git tag 命令來指定應用程式的版本,這樣就行了。除此之外,無需其他任何設定,建置腳本裡面也不用寫任何與版本編號有關的程式碼。參考範例:FlubuCore_UsingMinVer.cs。
第 25 行的 BuildConfiguration 屬性設定為 "Release",代表建置專案時所使用的組態名稱。這個組態名稱就是對應到你在 Visual Studio 的 Configuration Manager 視窗裡建立的組態,通常會有 "Debug" 和 "Release" 兩種組態,可分別為「除錯」和「發行」這兩種場景提供不同的建置與部署設定。
另外,通常我們不需要為 "build"(前面範例中的 "
建置腳本寫好之後,先編譯這個專案,確認無誤之後,就可以到命令列視窗執行建置指令了。
其中的 "
執行過程看起來會像這樣:
請注意前面幾行字,它們的意思是:「你沒有指明建置腳本檔案的所在路徑,所以我會開始到幾個預設的目錄底下尋找建置腳本檔案。」
接著下一行又說:「找到了,會使用這個腳本檔案:'build/BuildScript.cs'.」
這也就呼應了稍早提過的,建立 build script 專案時,專案名稱和建置腳本的檔案名稱最好都按照慣例,便可避免一些麻煩。
官方文件有列出預設的(會自動搜尋的)建置腳本目錄和檔案名稱,如下所示(醒目標示的項目是我偏好的命名組合):
此指令執行完畢後,便會在你執行該指令的所在目錄下產生一個名為 ".flubu" 的純文字檔案,裡面的內容就是你在上圖中回答的兩個檔案名稱,而且檔案路徑是採用相對路徑名,就像這樣:
第 25 行的 BuildConfiguration 屬性設定為 "Release",代表建置專案時所使用的組態名稱。這個組態名稱就是對應到你在 Visual Studio 的 Configuration Manager 視窗裡建立的組態,通常會有 "Debug" 和 "Release" 兩種組態,可分別為「除錯」和「發行」這兩種場景提供不同的建置與部署設定。
另外,通常我們不需要為 "build"(前面範例中的 "
compile
" 任務)指定特別的輸出路徑。預設情況下,編譯過的 .DLL 和 .EXE 檔案都會輸出至專案的 bin/debug/[目標框架]/ 目錄下,而一般建議是就讓它們留在那裡。另一方面,當我們要執行打包(pack)、部署(deploy)、發布(publish)等工作時,則通常會指定一個特定的輸出目錄。建置腳本寫好之後,先編譯這個專案,確認無誤之後,就可以到命令列視窗執行建置指令了。
執行 build script
開啟命令列視窗,並將現行目錄切換至專案所在的 source 目錄,然後輸入以下指令來執行建置腳本:flubu compile
其中的 "
compile
" 就是欲執行的目標工作(target),名稱對應到前面的 BuildScript.cs 裡面的第 41 行(傳入 CreateTarget
方法的字串)。執行過程看起來會像這樣:
請注意前面幾行字,它們的意思是:「你沒有指明建置腳本檔案的所在路徑,所以我會開始到幾個預設的目錄底下尋找建置腳本檔案。」
接著下一行又說:「找到了,會使用這個腳本檔案:'build/BuildScript.cs'.」
這也就呼應了稍早提過的,建立 build script 專案時,專案名稱和建置腳本的檔案名稱最好都按照慣例,便可避免一些麻煩。
官方文件有列出預設的(會自動搜尋的)建置腳本目錄和檔案名稱,如下所示(醒目標示的項目是我偏好的命名組合):
- Build.cs
- BuildScript.cs
- DeployScript.cs
- DeploymentScript.cs
- _Build/Build.cs
- _Build/BuildScript.cs
- Build/Build.cs
- Build/BuildScript.cs
- _BuildScript/BuildScript.cs
- _BuildScripts/BuildScript.cs
- BuildScript/BuildScript.cs
- buildscript/deployscript.cs
- buildscripts/buildscript.cs
- buildscripts/deployscript.cs
- BuildScript/DeploymentScript.cs
- BuildScripts/DeploymentScript.cs
使用 .flubu 檔案
如果你的建置腳本專案放在比較特殊的路徑,或者使用了比較特別的檔案名稱,你還可以使用flubu setup
指令來建立一個組態檔。這個指令會以問答的方式要你輸入建置腳本的 .cs 檔案名稱以及建置腳本專案的 .csproj 檔案名稱(二者皆使用相對路徑)。參考下圖:此指令執行完畢後,便會在你執行該指令的所在目錄下產生一個名為 ".flubu" 的純文字檔案,裡面的內容就是你在上圖中回答的兩個檔案名稱,而且檔案路徑是採用相對路徑名,就像這樣:
build/BuildScript.cs
build/build.csproj
結語
初次使用 FlubuCore,目前覺得挺好。儘管 FlubuCore 也支援 GitVersion,但我嘗試搭配使用 GitVersion 來設定組件版本編號之後,覺得沒有特別方便,因為每次建置專案時,我老是得去猜 GitVersion 這次使用的版本編號是否跟我所想的一樣,徒增煩惱。後來,我發現另一個更直觀、更方便的套件:MinVer。所以在更新本文的時候,也加入了 MinVer 的相關說明與範例程式碼。另外,本文也有提到 Flubu 命令列工具能夠產生 .flubu 檔案,以便紀錄建置腳本檔案的所在路徑。這個 .flubu 檔案的內容雖然簡單(內容只有兩行文字),但是卻扮演了相當重要的角色,因為它解決了建置腳本的一個重要問題:如何決定工作目錄,以便在編寫建置腳本時能夠使用相對路徑名。有關這個部分,我會在下一篇文章裡進一步說明。
Happy building!