.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では、ビルド前イベント(Pre-build event)にスクリプトを追加することで、プロジェクトバージョンの自動更新を実現できます。具体的な操作は以下の通りです。プロジェクトのプロパティで「ビルドイベント」タブを見つけ、「ビルド前イベントのコマンドライン(Pre-build event command line)」に以下のコマンドを追加します。
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タグに基づいてプログラムバージョンを自動的に更新します。
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]
# 直近のタグ、チェックアウトハッシュ値
$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
このスクリプトは、まず3つのパラメータ(AssemblyInfoFile:アセンブリ情報ファイルのパス、Configuration:構成名、Platform:プラットフォーム名)を受け取ります。次に、ファイルが存在するかチェックし、存在しない場合はエラーをスローします。続いて、現在の日時やGitタグ作成時刻などの情報を取得し、バージョン番号の各部分を計算します。構成とプラットフォーム情報に基づいて、新しいAssemblyProductとAssemblyFileVersionを生成します。最後に、正規表現を使用してファイル内の古いバージョン情報を置き換え、更新された内容をAssemblyInfo.csファイルに書き込むことで、プログラムバージョンの自動更新を実現します。
これらのスクリプトと方法を通じて、.NETプロジェクトの開発効率を大幅に向上させ、バージョン管理と公開プロセスの自動化を実現できます。これらの内容が皆様の開発作業に役立ち、.NET開発の道をよりスムーズに進められることを願っています。
上記のサンプルスクリプトは、オープンソースプロジェクトで見つけることができます:dotnet9/CodeWF.Toolbox: CodeWF Toolbox 使用 Avalonia 开发的跨平台工具箱 Cross platform toolbox developed using Avalonia