前言#
去年年底、Snap Genshin プロジェクトがアーカイブされ、Snap Hutao に置き換えられました。新世代のアプリケーションでは、プロジェクトは更新された技術を使用し、winui3 が元の WPF に置き換えられ、最終的に msix インストーラーにパッケージ化され、Microsoft ストアに上架されました。ストアの審査メカニズムのため、アプリは以前の自己配布モードのようにいつでも更新をプッシュすることができなくなったため、開発者がテストするための CI/CD チャンネルバージョンを構築することがより重要になりました。そのため、私は Azure DevOps の Pipelines を使用して、GitHub との統合を通じて CI/CD パイプラインを作成しました。
DevOps アカウントの作成#
-
Microsoft Azure Pipelines ホームページ にアクセスし、GitHub で無料で始めるをクリックして、Microsoft アカウントでログインし、Azure DevOps パネルにアクセスして GitHub アカウントをバインドします。
-
チームや会社のためにこの環境を作成する場合は、チームの Microsoft アカウントを使用し、GitHub バインドプロセス中に Azure DevOps にチームリポジトリデータの使用を許可することをお勧めします。
- 同時に、チームの DevOps チーム名を作成する必要があります。
- 無料枠が必要なオープンソースプロジェクトの場合は、このフォームを追加するか、
[email protected]
にメールを送信して無料枠を申請する必要があります。
-
Microsoft があなたの組織に無料枠を追加するのを待つために 1-2 日待つ必要があります。この間、CI/CD パイプラインを構築し続けることはできますが、枠が不足しているため実際には実行できません。
プロジェクトの作成#
-
DevOps パネルに入り、組織ページに移動し、右側の
New Project
をクリックして新しいプロジェクトを作成します。 -
作成に成功したら、
GitHub
をコードリポジトリとして選択します。 -
コードリポジトリを選択する際、フィルタで
All repositories
を選択し、CI パイプラインを作成する必要があるプロジェクトを見つけて確認します。
-
その後、ページは GitHub 認証ページにリダイレクトされ、ここで Azure DevOps にそのリポジトリを編集することを同意します。
-
認証が完了すると、
YAML
ファイルエディタにリダイレクトされ、これが Azure Pipelines の設定ファイルです。
パイプラインの構築#
[tip type="info" title="互換性の問題"]
Microsoft 公式ドキュメント では、Microsoft が公式にメンテナンスしている Azure Pipelines プラグインを推奨していますが、この記事執筆時点では VS 2022 に互換性の問題があります。そのため、Snap Hutao プロジェクトを構築する際、私は PowerShell を使用してコマンドラインでアプリケーションをパッケージ化しました。したがって、この記事を通じて MSIX パッケージ化の詳細なプロセスを理解することもできます。
[/tip]
準備作業#
すべてが始まる前に、パイプライン環境のためにいくつかの環境変数を設定します。
build_date
は、環境内の PowerShell を呼び出すことで2023.2.28
のような時間形式を返します。このような日付を CI/CD テストチャンネル内のソフトウェアのバージョン番号として使用します。
variables:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
solution: '$(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao.sln'
project: '$(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj'
buildPlatform: 'x64'
buildConfiguration: 'Release'
build_date: $[ format('{0:yyyy}.{0:M}.{0:d}', pipeline.startTime) ]
CI/CD 環境を Windows Server 2022 に設定し、この環境には Visual Studio 2022 エンタープライズ版が含まれています。
pool:
vmImage: 'windows-2022'
バイナリファイルのコンパイル#
- 次に、.NET Framework プログラムのパッケージ環境を作成します。
- task: UseDotNet@2
displayName: Install dotNet
inputs:
packageType: 'sdk'
version: '7.x'
includePreviewVersions: true
- task: NuGetToolInstaller@1
name: 'NuGetToolInstaller'
displayName: 'NuGet Installer'
- task: NuGetCommand@2
displayName: NuGet restore
inputs:
command: 'restore'
restoreSolution: '$(solution)'
feedsToUse: 'select'
その後、Visual Studio 2022 に含まれる MSBuild
を使用してコードをコンパイルできます。
- このステップでは、ほとんどの場合、
msbuildLocationMethod
をversion
に設定し、msbuildVersion
をlatest
または他の指定バージョンに設定するだけで済みます。しかし、VS2022 の互換性の問題のため、location
とMSBuild.exe
のパスをパッケージ化パラメータとして使用せざるを得ません。
- task: MsixPackaging@1
displayName: Build binary package
inputs:
outputPath: '$(Build.ArtifactStagingDirectory)/'
solution: '$(solution)'
clean: false
generateBundle: false
buildConfiguration: 'Release'
buildPlatform: 'x64'
updateAppVersion: false
appPackageDistributionMode: 'SideloadOnly'
msbuildLocationMethod: 'location'
msbuildLocation: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Msbuild\Current\Bin\MSBuild.exe'
MSIX パッケージ化#
パッケージ化の前に、パッケージ後のソフトウェアバージョン番号を準備する必要があります。コンパイルされたバイナリプログラムでは、ソフトウェアバージョン番号はコード内の設定に従いますが、CI/CD の一時バージョンのためにそれを変更することはできません。したがって、CI/CD パイプラインが私たちのためにこの一時的なバージョン番号を準備する必要があります。CI/CD パイプラインが最初に実行されるとき、私たちは環境変数を通じて 2023.2.28
のような形式の日時を取得しましたが、4 番目の revision number
が欠けています。非常に偶然なことに、Azure Pipelines は各 CI/CD タスクにバージョン番号を作成し、その形式は 20230228.1
のようになります。実際、小数点以下の数字はその日付の下でのタスクの回数を示しており、この数字は revision number
に非常に適しています。なぜなら、バージョン番号が必ず順序的に増加することを保証できるからです。
Azure DevOps Marketplace では、GetRevision
という名前のプラグインを追加できます。これを使用すると、以下のスクリプトを追加して rev_number
変数に revision number を設定できます。
- task: GetRevision@1
displayName: get Pipelines revision number
inputs:
VariableName: 'rev_number'
追加のパラメータを指定しない限り、コンパイルされたプログラムはプロジェクトディレクトリの \bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\
ディレクトリに保存されます。
Windows システムは、MSIX アプリの Identity Name
を読み取ることでアプリの一意の識別子として使用します。したがって、CI/CD バージョンアプリと正式版アプリを区別するために、いくつかの情報を変更する必要があります。ここでは、MagicChunks
を使用して、これらの属性を管理する AppxManifest.xml
ファイルを変更します。
transformations
には、私たちが上書きする属性値が含まれています。Package/Identity/@Name
は、システムがソフトウェアパッケージの一意の識別を行うための名前です。Package/Identity/@Publisher
は重要な開発者情報で、その値は MSIX アプリパッケージの署名と完全に一致する必要があります。そうしないと署名エラーが発生します。- コード署名証明書が購入されたものである場合、時には会社名、組織名、メールアドレスなどの複数の情報が含まれることがあります。この場合、一部の句読点が
xml
形式と衝突することがあります。したがって、これらの情報の中で衝突する記号をエスケープし、これらのすべての情報を含める必要があります。単にCN
のみではありません。
- コード署名証明書が購入されたものである場合、時には会社名、組織名、メールアドレスなどの複数の情報が含まれることがあります。この場合、一部の句読点が
"Package/Identity/@Version": "$(build_date).$(rev_number)"
の行は、以前に準備したアプリパッケージバージョンを属性に書き込みます。
- task: MagicChunks@2
inputs:
sourcePath: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\AppxManifest.xml'
fileType: 'Xml'
targetPathType: 'source'
transformationType: 'json'
transformations: |
{
"Package/Identity/@Name": "7f0db578-026f-4e0b-a75b-d5d06bb0a74c",
"Package/Identity/@Publisher": "CN=DGP Studio CI",
"Package/Identity/@Version": "$(build_date).$(rev_number)",
"Package/Properties/DisplayName": "胡桃 Alpha",
"Package/Properties/PublisherDisplayName":"DGP Studio CI",
"Package/Applications/Application/uap:VisualElements/@DisplayName": "胡桃 Alpha"
}
次に、アプリケーションで使用される静的リソースもバイナリプログラムディレクトリに追加します。これらのリソースはコード内で外部呼び出しとして扱われるため、バイナリコンパイルプロセス中に自動的にコンパイル後のディレクトリに追加されることはありません。
- task: CmdLine@2
displayName: Create resources folder
inputs:
script: |
mkdir Assets
mkdir Resource
workingDirectory: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64'
- task: CopyFiles@2
displayName: Copy Assets Folder
inputs:
SourceFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\Assets'
Contents: '**'
TargetFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\Assets'
- task: CopyFiles@2
displayName: Copy Resource Folder
inputs:
SourceFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\Resource'
Contents: '**'
TargetFolder: '$(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64\Resource'
すべてが整ったので、makeappx
を使用してバイナリファイルを MSIX アプリパッケージにパッケージ化できます。
- その中で、
$(Build.ArtifactStagingDirectory)
は Azure Pipelines のデフォルトのエクスポートリソースディレクトリです。
- task: CmdLine@2
displayName: Build MSIX
inputs:
script: '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\makeappx.exe" pack /d $(Build.SourcesDirectory)\src\Snap.Hutao\Snap.Hutao\bin\x64\Release\net7.0-windows10.0.18362.0\win10-x64 /p $(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(build_date).$(rev_number).msix'
MSIX アプリパッケージの署名#
MSIX アプリパッケージは、すべてのアプリがコード署名されることを要求します。そうしないとアプリはインストールできません。したがって、次に、パッケージ化された MSIX パッケージに署名を行います。
Pipelines メニューの Library
をクリックし、Secure files
に移動して、パスワード付きの pfx 証明書ファイルをアップロードするボタンをクリックします。
Pipelines YAML ファイルエディタに戻り、pfx 証明書のパスワードをこのパイプラインタスク内の変数として保存する必要があります。右上の Variables
をクリックし、追加をクリックします。変数の追加ウィンドウで、変数に名前を設定し、Value
にパスワードを入力し、最後に Keep this value secret
にチェックを入れます。
これで、Microsoft の公式 MsixSigning
プラグインを使用して MSIX アプリパッケージに署名できます。
- ここで
certificate
はSecure Files
にアップロードした証明書ファイル名です。 passwordVariable
は pfx 証明書パスワードを保存した変数名です。
- task: MsixSigning@1
name: signMsix
displayName: Sign MSIX package
inputs:
package: '$(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(build_date).$(rev_number).msix'
certificate: 'DGP_Studio_CI.pfx'
passwordVariable: 'pw'
PowerShell または CMD を使用して署名する場合は、以下のコマンドを参考にしてください。
SignTool sign /fd SHA256 /a /f C:\Users\i\Documents\GitHub\Snap.Hutao.Output\Snap.Hutao_TemporaryKey.pfx /p defaultpassword C:\Users\i\Documents\GitHub\Snap.Hutao.Output\Snap.Hutao.signed.msix
CI/CD アプリの公開#
Snap Hutao プロジェクトでは、サイドロードパッケージと CI/CD サイドロード証明書を一緒に pre-release
の形で GitHub メインプロジェクトリポジトリに公開することに決めました。その中で、
Download Root CA
タスクは、Secure Files
に保存されているサイドロード証明書を CI/CD 環境にダウンロードし、そのファイルをcerFile
名で環境変数に保存します。GitHub Release 公開プロセスでは、$(cerFile.secureFilePath)
を使用してそのファイルを参照できます。gitHubConnection
は統合された GitHub アカウントです。
- task: DownloadSecureFile@1
name: cerFile
displayName: Download Root CA
inputs:
secureFile: 'Snap.Hutao.CI.cer'
- task: GitHubRelease@1
inputs:
gitHubConnection: 'github.com_Masterain'
repositoryName: 'DGP-Studio/Snap.Hutao'
action: 'create'
target: '$(Build.SourceVersion)'
tagSource: 'userSpecifiedTag'
tag: '$(build_date).$(rev_number)'
title: '$(build_date).$(rev_number)'
releaseNotesSource: 'inline'
releaseNotesInline: |
## 普通ユーザーはダウンロードしないでください
このバージョンは CI プログラムによって自動的にパッケージ化された `Alpha` テストバージョンであり、**開発者のテスト用にのみ使用してください**。
普通のユーザーは[こちらをクリック](https://github.com/DGP-Studio/Snap.Hutao/releases/latest/)して最新の安定版をダウンロードしてください。
assets: |
$(Build.ArtifactStagingDirectory)/*
$(cerFile.secureFilePath)
isPreRelease: true
changeLogCompareToRelease: 'lastFullRelease'
changeLogType: 'commitBased'
成果#
YAML エディタの右上隅にある保存をクリックすると、CI/CD 設定ファイルが GitHub リポジトリに追加され、すぐに一度実行されます。Azure DevOps では、Pipelines のすべてのタスク記録を見ることができます。
GitHub Release では、公開された CI/CD バージョンを見ることができます。
対応するコミットでは、対応する CI/CD タスクの情報も見ることができます。