ツナ缶雑記

ぐうたらSEのブログです。主にマイクロソフト系技術を中心に扱います。

App.config に対して XML 変換を行う Azure Pipelines の YAML テンプレートを作る

f:id:masatsuna:20200422160213p:plain

ASP.NET のプロジェクトを作成すると、 Web.config ファイルが生成されます。 それと同時に、Web.Debug.config と Web.Release.config が作成され、アプリケーションの発行を行う際の構成にあわせて、 Web.config の変換を行ってくれます。 今回はこの構成ファイルの書き換え機能を App.config に対して実行できるような Azure Pipelines のテンプレートを作ってみようと思います。

環境

  • Visual Studio 2019
  • .NET Framework 4.8
  • コンソールアプリケーション(App.config のあるプロジェクトなら同じことができます)

プロジェクトを準備する

まずは適当にコンソールアプリケーションを作成します。 超シンプルに、 AppSettings から値を取得してコンソールに表示するだけにしておきます。

using System;
using System.Configuration;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Setting1: {ConfigurationManager.AppSettings["Setting1"]}");
        }
    }
}

App.config はこのような形で、 AppSettings に 1 つだけキーを足しておきます。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="Setting1" value="LocalDebugSetting"/>
  </appSettings>
</configuration>

実行するとこんな感じです。

f:id:masatsuna:20200422141828p:plain
実行結果

差し替える構成ファイルを準備する

さて、ここから本番です。 今回は App.config に設定されている Settings1 の値を、ビルド時に差し替えるような XML 変換のファイルを作っていきます。 Web.config の場合 Release で発行したときは Web.Release.config の XML 変換が適用されます。 似たような構成にするため、以下のような App.Release.config を作ります。

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add key="Setting1" value="ReleaseSetting" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
  </appSettings>
</configuration>

ファイルのプロパティは以下のように設定しておきます。

f:id:masatsuna:20200422142534p:plain
App.Release.config のプロパティ

ソリューション上は下記のようになります。

f:id:masatsuna:20200422142419p:plain
App.Release.config を追加する

YAML テンプレートを準備する

続いて今回のキモとなる、 YAML のテンプレートを作成します。 .git ディレクトリのあるルートディレクトリ内に、 pipelines-template ディレクトリを作成し、その中に以下の YAML を配置します。 ファイル名は publish-desktop-app-template.yml としておきました。

parameters:
- name: projectRootDirectory
  type: string
  default: ''
- name: projectFileName
  type: string
  default: '*.csproj'
- name: outputPath
  type: string
  default: ''
- name: buildPlatform
  type: string
  default: 'AnyCPU'
- name: buildConfiguration
  type: string
  default: 'Release'

steps:
  - task: Bash@3
    displayName: 'パラメーターチェック'
    inputs:
      targetType: 'inline'
      script: |
        if [ -z "$PROJECTROOTDIRECTORY" ]; then
          echo "##vso[task.logissue type=error;]テンプレートパラメーター \"projectRootDirectory\" が指定されていません。"
          echo "##vso[task.complete result=Failed;]"
        fi
        if [ -z "$OUTPUTPATH" ]; then
          echo "##vso[task.logissue type=error;]テンプレートパラメーター \"outputPath\" が指定されていません。"
          echo "##vso[task.complete result=Failed;]"
        fi
    env:
      PROJECTROOTDIRECTORY: ${{ parameters.projectRootDirectory }}
      OUTPUTPATH: ${{ parameters.outputPath }}
  - task: FileTransform@2
    displayName: 'App.config 変換 - ${{ parameters.projectRootDirectory }}'
    inputs:
      folderPath: '${{ parameters.projectRootDirectory }}'
      xmlTransformationRules: '-transform "**\App.${{ parameters.buildConfiguration }}.config" -xml "**\App.config"'
  - task: VSBuild@1
    displayName: 'アプリケーションのビルド - ${{ parameters.projectRootDirectory }}'
    inputs:
      solution: '${{ parameters.projectRootDirectory }}/**/${{ parameters.projectFileName }}'
      msbuildArgs: '/p:OutPutPath="${{ parameters.outputPath }}"'
      platform: '${{ parameters.buildPlatform }}'
      configuration: '${{ parameters.buildConfiguration }}'

ここまで作成したら Azure DevOps のリポジトリにファイル一式をプッシュしておきます。

ビルドパイプラインを作成する

続いて Azure DevOps から、ビルドパイプラインの YAML を作成していきます。 作成したテンプレートを呼び出すようにしましょう。 また動作確認のため、最終的にビルドしたアプリケーションを Pipeline Artifacts に登録しておきます。

trigger: none

pool:
  vmImage: 'windows-latest'

steps:
- template: 'pipelines-template/publish-desktop-app-template.yml'
  parameters:
    projectRootDirectory: '$(Build.SourcesDirectory)/ConfigTransformationSample/ConsoleApp1'
    outputPath: '$(Build.Artifactstagingdirectory)/ConsoleApps/ConsoleApp1'
- task: PublishPipelineArtifact@1
  inputs:
    targetPath: '$(build.ArtifactStagingDirectory)\ConsoleApps'
    artifact: 'ConsoleApplications'
    publishLocation: 'pipeline'

結果確認

上記のビルドパイプラインを実行すると、構成ファイルの変換が実行され、Pipeline Artifacts には以下の構成ファイルを含むアプリケーションが配置されているはずです。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <appSettings>
        <add key="Setting1" value="ReleaseSetting" />
    </appSettings>
</configuration>

これで ASP.NET のアプリケーションと同じような方法で、構成ファイルの XML 変換を実行できるようになりました。

まとめ

今回は ASP.NET Web アプリケーションの発行のような形で、デスクトップアプリケーションのビルドができる YAML テンプレートを作ってみました。 カスタマイズして使ってみてください。

注意点

テンプレートに渡す sourceDirectory の配下には、 プロジェクトを 1 つだけ置くようにしましょう。 ここにルートディレクトリを渡してしまうと、 App.config の書き換えが思ったようにいかなくなります。 これは FileTransform のタスクの制約なのであきらめるしかなさそうです。

本稿で解説した YAML について

以下の GitHub リポジトリに公開してあります。

AzurePipelinesYAMLSample/AppConfigTransform at master · tsuna-can-se/AzurePipelinesYAMLSample · GitHub

なお一部のコードについて、本稿で解説した物とは異なる箇所があります。