在.net 開發的旅程中,高效的版本管理和便捷的發布流程是提升開發效率和項目質量的關鍵環節。今天,我們就來深入探討一下如何利用腳本實現.net avalonia ui 項目(當然,這些方法也適用於其他.net 項目)的自動更新程式版本以及一鍵發布,讓你的開發過程更加流暢和高效。
powershell 腳本執行權限檢查
在運行 powershell 腳本之前,了解並正確設置執行策略是至關重要的。執行策略決定了 powershell 是否允許運行腳本以及運行何種類型的腳本。你可以使用以下簡單的命令來查看當前的執行策略:
Get-ExecutionPolicy
不同的執行策略值有著不同的含義,對腳本的運行有著不同程度的限制:
- restricted:這是默認策略,它就像是一個嚴格的門衛,不允許運行任何腳本,你只能在 powershell 控制台中逐行輸入命令。這在一定程度上保證了系統的安全性,但對於需要批量執行腳本的開發者來說,無疑是一種束縛。
- allsigned:只允許運行由受信任的發布者簽名的腳本。這就好比只允許持有特定通行證的人進入,確保了腳本來源的可靠性,但也增加了腳本使用的門檻,因為並非所有腳本都有簽名。
- remotesigned:本地創建的腳本可以直接運行,而從網際網路下載的腳本必須由受信任的發布者簽名才能運行。這是一個在安全性和便捷性之間取得平衡的設置,既允許本地開發的靈活性,又對網絡下載的腳本進行了安全把關。
- unrestricted:允許運行所有腳本,不過從網際網路下載的腳本在運行前會提示確認。這給予了開發者極大的自由度,但也伴隨著一定的安全風險,因為未經嚴格檢查的腳本可能攜帶惡意代碼。
- bypass:不阻止任何腳本的運行,也不會有安全提示。這是一個非常開放的設置,一般僅在特定的、安全可控的環境中使用,否則可能會讓系統暴露在安全威脅之下。
默認情況下,執行策略是 restricted,這可能會導致回寫文件失敗,提示不允許寫入流。例如,當你嘗試運行一個需要修改文件內容的腳本時,就會遇到權限問題。
修改執行策略
為了能夠順利運行腳本,我們需要根據自己的需求選擇合適的執行策略。如果希望在保證一定安全性的同時,能夠方便地運行本地腳本和經過一定安全檢查的網絡下載腳本,將執行策略設置為 remotesigned 是一個不錯的選擇。
但需要注意的是,修改執行策略可能需要管理員權限,所以請務必以管理員身份運行 powershell,然後使用以下命令進行修改:
Set-ExecutionPolicy RemoteSigned
這樣,本地創建的腳本可以直接運行,而從網際網路下載的腳本則需要經過簽名驗證,有效降低了安全風險。
驗證修改結果
修改執行策略後,為了確保設置生效,你可以再次使用 get-executionpolicy 命令來驗證是否修改成功。當看到輸出結果為 remotesigned 時,就意味著你已經成功修改了執行策略,之後應該就可以正常運行.ps1 腳本了。
vs 發布
在 visual studio 中,我們可以通過在預生成事件中添加腳本來實現項目版本的自動更新。具體操作如下:在項目屬性中找到 “生成事件” 選項卡,在 “預生成事件命令行” 中添加以下命令:
powershell -ExecutionPolicy Bypass -File "UpdateAssemblyVersion.ps1" -AssemblyInfoFile "GlobalAssembly.cs" -Configuration "$(ConfigurationName)" -Platform "$(PlatformName)"
這裡的參數有著明確的含義:
- configurationname:表示活動解決方案配置,常見的如 debug(調試模式)和 release(發布模式)。在不同的配置下,我們可能希望生成不同版本號的程式,以區分開發和正式發布的版本。
- platformname:表示活動解決方案平台,例如 anycpu(適用於任何 cpu 架構)、x86(32 位架構)、x64(64 位架構)等。不同的平台可能需要不同的版本標識,以滿足兼容性和性能需求。
批處理文件發布
有時候,我們可能希望在不打開 visual studio 的情況下發布程式,並且能夠方便地擴展到發布 windows、linux、macos 等多個平台。這時候,批處理文件就派上用場了。以下是一個示例批處理文件:
@echo off
setlocal enabledelayedexpansion
rem 遍历 GlobalAssemblies 目录下的文件执行 PowerShell 脚本
for %%f in (GlobalAssemblies\*) do (
powershell -ExecutionPolicy Bypass -File "UpdateAssemblyVersion.ps1" -AssemblyInfoFile "%%f" -Configuration "Release" -Platform "x64"
rem 检查 PowerShell 脚本执行是否成功
if !errorlevel! neq 0 (
echo Failed to update assembly version for file %%f!
endlocal
exit /b !errorlevel!
)
)
rem 设置发布路径
set PUBLISH_PATH=publish\win-x64
rem 定义项目信息数组,格式为 项目名称,项目路径(只写项目目录),相对发布目录名
set "projects=码坊工具箱,src\CodeWF.Toolbox.Desktop,codewf Avalonia发布测试,tests\AvaloniaAotDemo,AvaloniaAotDemo"
rem 遍历项目数组
for %%a in ("%projects: =","%") do (
set "current_project=%%~a"
for /f "tokens=1,2,3 delims=," %%b in ("!current_project!") do (
set "projectName=%%b"
set "projectPath=%%c"
set "relativePublishDir=%%d"
rem 拼接 .pubxml 文件的默认路径
set "pubxmlPath=!projectPath!\Properties\PublishProfiles\FolderProfile-win_x64.pubxml"
rem 拼接当前项目的发布路径
set "CURRENT_PUBLISH_DIR=!PUBLISH_PATH!\!relativePublishDir!"
echo "projectName after assignment: !projectName!"
echo "projectPath after assignment: !projectPath!"
echo "relativePublishDir after assignment: !relativePublishDir!"
echo "pubxmlPath after assignment: !pubxmlPath!"
echo "current publish dir after assignment: !CURRENT_PUBLISH_DIR!"
echo Publishing !projectName! for win-64...
rem 清空发布目录
if exist "!CURRENT_PUBLISH_DIR!" (
rd /s /q "!CURRENT_PUBLISH_DIR!"
)
rem 创建发布目录
mkdir /p "!CURRENT_PUBLISH_DIR!" 2>nul
rem 执行 dotnet publish 命令进行 AOT 发布,并指定目标框架
dotnet publish "!projectPath!" /p:PublishProfile="!pubxmlPath!" -f net9.0-windows -o "!CURRENT_PUBLISH_DIR!"
rem 检查 dotnet publish 命令的退出代码
if !errorlevel! neq 0 (
echo Publish of !projectName! failed!
endlocal
exit /b !errorlevel!
)
rem 检查发布目录是否存在
if exist "!CURRENT_PUBLISH_DIR!" (
rem 删除调试符号文件
del "!CURRENT_PUBLISH_DIR!\*.pdb"
)
echo Publish of !projectName! succeeded!
echo Published files of !projectName! are located at: "!CURRENT_PUBLISH_DIR!"
)
)
endlocal
這個批處理文件首先遍歷 globalassemblies 目錄下的文件,執行 powershell 腳本來更新程式版本。然後,它定義了項目信息數組,包括項目名稱、項目路徑和相對發布目錄名。接著,通過循環遍歷項目數組,依次對每個項目進行發布操作。在發布過程中,先清空發布目錄,再創建新的發布目錄,然後執行 dotnet publish 命令進行 aot 發布,並指定目標框架為 net9.0-windows。最後,檢查發布是否成功,如果成功則刪除調試符號文件,並輸出成功信息和發布路徑。
powershell 腳本實現自動版本更新
下面這個 powershell 腳本用於根據 git 標籤(tag)自動更新程式版本:
param(
[Parameter(Mandatory=$true)]
[string]$AssemblyInfoFile,
[Parameter(Mandatory=$true)]
[string]$Configuration,
[Parameter(Mandatory=$true)]
[string]$Platform
)
# 检查文件是否存在
if (-not (Test-Path $AssemblyInfoFile)) {
throw "错误:文件 $AssemblyInfoFile 不存在"
}
Write-Output "AssemblyInfoFile: $AssemblyInfoFile"
Write-Output "Configuration: $Configuration"
Write-Output "Platform: $Platform"
#获取当前日期时间,并生成格式化的时间戳
$currentDateTime =Get-Date
#获取当前分支,签出标签创建时间[基准时间]
$strBranchCreateTime =git log -1 --format=%ai $latest_tag
$dateBranchCreateTime=[DateTime]::Parse($strBranchCreateTime)
#时间差的总分数
$timeDifMinutes =[math]::Round(($currentDateTime-$dateBranchcreateTime).TotalMinutes)
#版本号格式处理成x.x.65535.65535
$yy=[math]::Floor($timeDifMinutes/65535)
$thirdInfo=$timeDifMinutes-$yy*65535
#读取文件内容
$content = Get-Content -Path $AssemblyInfoFile -Encoding Unicode
#使用正则表达式获职 AssemblyProduct 的值
$productPattern='^\[assembly: AssemblyProduct\("([^"]+)"\)\]'
$product = ""
#查找包含 AssemblyProduct 的行,并匹配正则表达式
foreach($line in $content){
if($line -match $productPattern){
$product= $matches[1]
break #找到匹配后退出循环
}
}
$items=$product -split '_'
$product=$items[0]
#当前最近标签、checkout hash值
$currentCommitHash=git describe --always --tag --long
$items=$currentCommitHash.Split('-')
$hashInfo=$items[$items.Length-1]
$firstFileVersion="0.0"
$secondFileVersion="100"
if($items.Length -eq 3)
{
$firstFileVersion=$items[0].Replace("v","");
$firstFileItems=$firstFileVersion.split('.');
$firstFileversion=$firstFileItems[0]+"."+$firstFileItems[1]
$secondFileVersion=$items[1]+"$yy".PadLeft(2,'0')
}
$platformInfo = ""
if ($Configuration -eq "Debug") {
$platformInfo = "D"
} elseif ($Configuration -eq "Release") {
$platformInfo = "R"
} else {
$platformInfo = "A"
}
switch ($Platform) {
"x86" {
$platformInfo += "-86"
}
"x64" {
$platformInfo += "-64"
}
"ARM" {
$platformInfo += "-ARM"
}
"AnyCPU" {
$platformInfo += "-AnyCPU"
}
default {
$platformInfo += "-Unknow"
}
}
#定义新的 AssemblyProduct和 AssemblyFileversion
$strDayInfo= $currentDateTime.Tostring("yyyyMMddHHmm")
$newAssemblyProduct = "$product"+"_"+"$platformInfo"+"_"+"$hashInfo"+"_"+"$strDayInfo"
if($secondFileVersion -eq "000")
{
$secondFileVersion="0"
}
$newAssemblyFileVersion = "$firstFileVersion"+"."+"$secondFileVersion"+"."+"$thirdInfo"
# 更新 AssemblyProduct
$content = $content -replace '^\[assembly: AssemblyProduct\(".*"\)\]', "[assembly: AssemblyProduct(`"$newAssemblyProduct`")]"
# 更新AssemblyVersion
$content = $content -replace '^\[assembly: AssemblyVersion\(".*"\)\]', "[assembly: AssemblyVersion(`"$newAssemblyFileVersion`")]"
# 更新AssemblyFileVersion
$content = $content -replace '^\[assembly: AssemblyFileVersion\(".*"\)\]', "[assembly: AssemblyFileVersion(`"$newAssemblyFileVersion`")]"
# 将更新后的内容写入 AssemblyInfo.cs 文件
Set-Content -Path $AssemblyInfoFile -Value $content -Encoding Unicode
這個腳本首先接收三個參數:assemblyinfofile(程式集信息文件路徑)、configuration(配置名稱)和 platform(平台名稱)。然後,它檢查文件是否存在,如果不存在則拋出錯誤。接著,通過獲取當前日期時間、git 標籤創建時間等信息,計算出版本號的各個部分。根據配置和平台信息,生成新的 assemblyproduct 和 assemblyfileversion。最後,使用正則表達式替換文件中的舊版本信息,將更新後的內容寫入 assemblyinfo.cs 文件,實現了程式版本的自動更新。
通過以上這些腳本和方法,我們可以極大地提高.net 項目的開發效率,實現版本管理和發布流程的自動化。希望這些內容能對你的開發工作有所幫助,讓你在.net 開發的道路上更加得心應手。
以上示例脚本可在开源项目找到:dotnet9/CodeWF.Toolbox: CodeWF Toolbox 使用 Avalonia 开发的跨平台工具箱 Cross platform toolbox developed using Avalonia