見出し画像

WindowsアプリのインストーラーをGitLab CIでビルド&デプロイする方法

こんにちは。株式会社SHIFT、RGAに出向中の水谷です。

少し前にある案件でWindowsアプリのCI/CD環境を作った際に、Windows インストーラーパッケージ(.msiファイル)も自動作成して、テスト環境にインストールするようにしたのですが、その手順が書かれている記事があまりないようなので書いておこうかと思います。


WiX Toolset

Windowsのインストーラーの作成方法はいくつかあるのですが、WiX Toolsetを使うのが一般的かなと思います。

WiX Toolsetは無料で使えるし、VisualStudioのエクステンションも存在するので、今回はストレートにこれを使うことにしました。

WiX Toolsetのインストール

WiX Toolsetのダウンロードはこちらからできます。

赤色のDOWNLOAD WIX V3.11.2をクリックして、WiX本体をダウンロードしてインストールします。続いて、WiX Toolset Visual Studio 2019 Extension(あるいはWiX Toolset Visual Studio 2019 Extension)もクリックしてインストールします。

インストーラープロジェクトの作成

Visual Studioのソリューションにインストーラーのプロジェクトを追加します。この際に、プロジェクトの種類としてSetup Project for WiX v3を選択します。

プロジェクトを追加すると、このようにProduct.wxsというxmlファイル形式のソースコードが自動生成されます。

Product.wxsの編集

インストーラーのソースコード(wxsファイル)は記述法にやや癖があるので、熟知した人以外はネットで調べながらトライ&エラーで進めることになります。

今回は、CSTestApp.exeというバイナリファイルを1だけをコピーし、デスクトップにショートカットアイコンを作るだけのシンプルなインストーラーにしたため、コードは以下のようになりました。

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="CSTestApp" Language="1033" Version="1.0.0.0" Manufacturer="RGA Inc" UpgradeCode="93763e51-01bc-4ffa-8971-3f20913d7c8b">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Platform="x64" />
        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
        <Feature Id="ProductFeature" Title="SetupProject" Level="1">
            <ComponentGroupRef Id="ProductComponents" />
            <ComponentGroupRef Id="ShortcutComponents" />
        </Feature>
        <MediaTemplate EmbedCab="yes" />
        <Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
        <UIRef Id="WixUI_InstallDir" />
        <UIRef Id="WixUI_ErrorProgressText"/>
    </Product>

    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFiles64Folder">
                <Directory Id="INSTALLFOLDER" Name="CSTestApp" />
            </Directory>
            <Directory Id="DesktopFolder" Name="Desktop" />
        </Directory>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
            <Component Id="ProductComponent1" Guid="{611067BF-9D3B-49E8-AFD5-776230C9B6AC}" Win64="yes" >
                <File Id="CSWinAppEXE" KeyPath="yes" Source="..\CSWinApp\bin\Release\net4.7.2-windows\CSWinApp.exe" />
            </Component>
        </ComponentGroup>
    </Fragment>

    <Fragment>
        <ComponentGroup Id="ShortcutComponents" Directory="DesktopFolder">
            <Component Id="ApplicationShortcut" Guid="F4231A9F-F6F5-4BFC-A687-BC8AD31E2DE3">
                <Shortcut Id="ApplicationDesktopShortcut" 
                    Name="CSTestApp"
                    Description="CSharp Test Application"
                    Target="[INSTALLFOLDER]CSWinApp.exe"
                    WorkingDirectory="INSTALLFOLDER"/>
                <RegistryValue
                    Root="HKCU"
                    Key="Software\RGA\CSWinApp"
                    Name="installed"
                    Type="integer"
                    Value="1"
                    KeyPath="yes"/>      
            </Component>
        </ComponentGroup>
    </Fragment>
</Wix>

コマンドラインでのビルド方法

インストーラーのビルドは、Visual StudioのIDE上では単純にソリューション全体をビルドするか、インストーラーのプロジェクトを指定してビルドすればよいのですが、コマンドライン上からビルドする場合は、(C/C++やC#などのコマンドラインビルドと同様に)msbuild.exeで行います。

今回はアプリ本体はC#で作成された"Any CPU"プラットフォーム向けアプリであるのに対して、インストーラーはx86プラットフォーム向けにビルドすることと、インストーラーのデバッグビルドが不要(デバッグビルドにする意味がほとんどないため)ということもあり、アプリ本体とインストーラーは別々にビルドすることにします。

このため、ビルドコマンドは次のようになります。

msbuild SetupProject.wixproj -p:Configuration=Release -p:Platform=x86 -fl -flp:logfile=installer_release.log

GitLab-CIへの組み込み

さて、今度はGitLab側の設定です。まずはGitLab Runnerにインストーラーのソースコードを開発したのと同じバージョンのWiX Toolsetをインストールしておきます。

続いて.gitlab-ci.ymlの作成ですが、以下がその例で、3つ目のmsbuild実行までがアプリのビルドで、4つ目のmsbuildがインストーラーのビルドになります。

stages:
  - build

msbuild:
  stage: build
  script:
    - 'cmd /C msbuild CSWinApp\CSWinApp.sln -t:restore'
    - 'cmd /C msbuild CSWinApp\CSWinApp.sln -p:Configuration=Release -p:Platform=''Any CPU'' -p:RunCodeAnalysis=true -fl -flp:logfile=build_release.log'
    - 'cmd /C msbuild CSWinApp\CSWinApp.sln -p:Configuration=Debug -p:Platform=''Any CPU'' -p:RunCodeAnalysis=true -fl -flp:logfile=build_debug.log'
    - 'cmd /C msbuild CSWinApp\SetupProject\SetupProject.wixproj -p:Configuration=Release -p:Platform=x86 -fl -flp:logfile=installer_release.log'
  artifacts:
    paths:
      - CSWinApp/CSWinApp/bin/
      - CSWinApp/SetupProject/bin/

サイレントインストール

Windowsインストーラーファイル(拡張子.msi)は、msiexec.exeに関連付けられており、GUIが表示されます。

CI/CDでデプロイする場合は、msiexec.exeを/qbオプションで実行することでサイレントインストールができます。

msixexec.exe /qb /i C:\App\CSWinApp.msi

また、サイレントアンインストールは以下のようになります。

msixexec.exe /qb /x C:\App\CSWinApp.msi

注意点としては、これらのコマンドはRunnerではなく、デプロイ先のマシンで実行する必要があることです。

今回のCI/CDでは、以下のPowershellスクリプトをRunner上でリモート実行することでこれを実現しました(事前にリモート実行のための設定が必要)。

# create credential for WinRM
$password = ConvertTo-SecureString <administrator password> -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("<ip address>\\Administrator", $password)

# terminate if running
Invoke-Command <ip address> -Credential $Cred -ScriptBlock { (get-process | ? name -like "CSWinApp").Kill() }

# uninstall if installed
Invoke-Command <ip address> -Credential $Cred -ScriptBlock { if (Test-Path 'C:/Program Files/CSTestApp') { msiexec.exe /qb /x C:\App\CSWinApp.msi } }

# copy the latest build from S3
Invoke-Command <ip address> -Credential $Cred -ScriptBlock { aws s3 cp "s3://<backetname>/CSWinApp.msi" C:\App\CSWinApp.msi } -ArgumentList "$($Args[0])"

# install the latest build
Invoke-Command <ip address> -Credential $Cred -ScriptBlock { msiexec /qb /i C:\App\CSWinApp.msi }

ちょっと手間がかかりますが、これで期待通りのCI/CDが動くと思います。
――――――――――――――――――――――――――――――――――

執筆者プロフィール:水谷 裕一
大手外資系IT企業で15年間テストエンジニアとして、多数のプロジェクトでテストの自動化作業を経験。その後画像処理系ベンチャーを経てSHIFTに自動化エンジニアとして入社。
SHIFTでは、テストの自動化案件を2件こなした後、株式会社リアルグローブ・オートメーティッド(RGA)に出向中。RGAでは副社長という立場でありながら、エンジニアとしてAnsibleやOpenshiftに関する案件も担当。また、Ansibleの社内教育や、外部セミナー講師も行っている。
最近の趣味は電動キックボードでの散歩。

【ご案内】
ITシステム開発やITインフラ運用の効率化、高速化、品質向上、その他、情シス部門の働き方改革など、IT自動化導入がもたらすメリットは様々ございます。

IT業務の自動化にご興味・ご関心ございましたら、まずは一度、IT自動化の専門家リアルグローブ・オートメーティッド(RGA)にご相談ください!

お問合せは以下の窓口までお願いいたします。

【お問い合わせ窓口】
代表窓口:info@rg-automated.jp
URL: https://rg-automated.jp