1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Linux 環境上で、C# のプロジェクトから NuGet パッケージを作成して他のプロジェクトに読み込ませる

Last updated at Posted at 2020-11-09

自分が担当している Azure Functions kafka Extensionだが、最近 Pull Request がおおいので、C#以外の言語のE2Eテストを書きたくなってきた。大抵の人は、C#のところだけみて、いろいろ変えるわけだけど、自分からすると、ちゃんと他言語でも動くんかいな?というのを毎回テストするのはめんどくさいので、仕組みを作ることにした。

現在のパッケージをビルドして、他言語のパッケージに読み込ませる時の課題

このプロジェクトは、もともとの Extension が C# で書かれている。そこで、作成された NuGet パッケージを使って、ほかの言語が動作するという感じなので次のことが必要だ。

  • Linux 上で、現在のソースから パッケージを作る。
  • Java, Python 等のパッケージで使っている csproj ファイルにそのパッケージを読み込ませる
  • サーバーを起動して、テストを行う

一見なんでもなさそうだがいくつかの考慮事項がある

  • ビルドするバージョンをどうするか?現在のプロジェクトのバージョンで素直にパッケージすると、現在のバージョンでパッケージされる。そうなると、NuGetソースから現在のバージョンがPublishされている場合、そちらを参照される可能性があるので、FalsePositveが発生しやすそう
  • Java, Python のパッケージ側から、読み込ませるバージョンを何にするか?バージョンが上がるたびに手動で変更するのはだるいので変更しなくていいようにしたい。
  • パッケージをどのように読み込ませるか?csproj ではファイル指定でパッケージの読み込みはできなさそう

結局どうしたかというと、100.100.100 などという、まぁ、そこまでアップデートしないだろう。ぐらいのバージョンを設定しておいて、ソースコードもそうしておくという単純な解決策にしておいた。もっと良いのがありそうだけど。

C# のパッケージのビルド

dotnet が既にインストールされていると想定すると、私はWSL2上で次のようなコマンドを書いて実行した。
重要なポイントは dotnet pack -o temp --include-symbols src/Microsoft.Azure.WebJobs.Extensions.Kafka/Microsoft.Azure.WebJobs.Extensions.Kafka.csproj /p:Version=100.100.100 パッケージを 100.100.100 というバージョンに指定して、pack を実行し、temp ディレクトリに出力している。その後、各言語用のディレクトリにコピーしている。それぞれの言語のディレクトリは Docker にパックされるように構成している。

# !/bin/bash

CURRENT_DIR=`pwd`
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd $DIR/..

WORKING_DIR=temp
if [ -d "$WORKING_DIR" ]; then rm -rf $WORKING_DIR; fi

dotnet pack -o temp --include-symbols src/Microsoft.Azure.WebJobs.Extensions.Kafka/Microsoft.Azure.WebJobs.Extensions.Kafka.csproj /p:Version=100.100.100


PACKAGE_DIR=test/Microsoft.Azure.WebJobs.Extensions.Kafka.LangEndToEndTests/server/java8/packages
if [ -d "$PACKAGE_DIR" ]; then rm -rf $PACKAGE_DIR; fi
mkdir $PACKAGE_DIR
cp temp/* $PACKAGE_DIR

cd $CURRENT_DIR

NuGet Source の指定

NuGetのファイルを読み込ませるためには、どうしたらいいだろう?と考えて、Local Source を設定して、読ませるという方法にした。現在は dotnet nuget add source というコマンドがあったので使ってみた。古い情報だと、mono をインストールして、nuget.exe を使うとかあったが、今は不要っぽい。

RUN dotnet nuget add source /workspace/packages/

ちなみに、このコマンドを発行すると、デフォルトの NuGet.Config が次のように更新される。最初は、バージョン固定の方法と、nuget source の読み込みの優先順位を変えて、必ずLocalが先に読ませるようにするとも考えたのだが、それだとやっぱりFalsePositiveが気になるので、バージョンの固定にした。

# pwd
/root/.nuget/NuGet
# cat NuGet.Config 
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  <add key="Package source 1" value="/workspace/packages/" />
</packageSources>

Java, Python 側の csproj ファイル

という仕様にしたので、Java, Python 側の csproj ファイルは、バージョンだけ、100.100.100.100 になったものになっている。これで自動的に現在のソースコードをビルドしたものが組み込まれるようになっている。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
	<WarningsAsErrors></WarningsAsErrors>
	<DefaultItemExcludes>**</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Kafka" Version="100.100.100" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.7" />
  </ItemGroup>
  <ItemGroup>
    <None Update="confluent_cloud_cacert.pem">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Dockerfile

最終的な Dockerfile は次の通りになっている。簡単でござった。

FROM mcr.microsoft.com/azure-functions/java:3.0-java8-core-tools

# Copy Local File
RUN mkdir /workspace
COPY . /workspace
WORKDIR /workspace
# dotnet 

ENV LD_LIBRARY_PATH=/workspace/target/azure-functions/kafka-function-20190419163130420/bin/runtimes/linux-x64/native

RUN dotnet nuget add source /workspace/packages/

RUN mvn clean package

ENTRYPOINT [ "/usr/bin/mvn", "azure-functions:run" ]

まとめ

C#の達人だったらもっといい方法思いつきそう。もしあったら是非教えてください。
この後、docker-compose で、Kafka サーバーと一緒に起動して動作するところまでいけたので、後は、E2E のフレームワークをC#で書いて、Azure DevOps に組み込んだら終了でござる。

補足 11/9/2020

しばやんさんからいいアドバイスをもらったので、パッケージリファレンスで実施することにしました。もうLocalNuget作らなくていいので、こちらの方がよさそうです。Dockerにパックするので、PackageReferenceは使えないと思い込んでいましたが、単純で、docker build のコンテキストをプロジェクトルートにしてしまえばよいです。ただ、コマンドのいい学びになったのでエントリは残しておきます。

image.png

extension.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
	<WarningsAsErrors></WarningsAsErrors>
	<DefaultItemExcludes>**</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.7" />
  </ItemGroup>
  <ItemGroup>
    <None Update="confluent_cloud_cacert.pem">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\..\..\src\Microsoft.Azure.WebJobs.Extensions.Kafka\Microsoft.Azure.WebJobs.Extensions.Kafka.csproj" />
  </ItemGroup>
</Project>

Dockerfile

FROM mcr.microsoft.com/azure-functions/java:3.0-java8-core-tools

# Copy Local File
RUN mkdir /workspace
COPY . /workspace
WORKDIR /workspace/test/Microsoft.Azure.WebJobs.Extensions.Kafka.LangEndToEndTests/server/java8
# dotnet 

ENV LD_LIBRARY_PATH=/workspace/target/azure-functions/kafka-function-20190419163130420/bin/runtimes/linux-x64/native

RUN mvn clean package

ENTRYPOINT [ "/usr/bin/mvn", "azure-functions:run" ]

docker build -t testj8 -f test/Microsoft.Azure.WebJobs.Extensions.Kafka.LangEndToEndTests/server/java8/Dockerfile . 

Resource

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?