0

I have a simple project dependency structure:

project A references project B

On my build server, both projects are built as Nuget packages: package A and package B.

In project B, I have the package version set to 2.0.0 manually. when I test building project A in Visual Studio, the Nuget package A produced has a dependency on package B of version 2.0.0. This is the desired behaviour.

On the build server however, we need to auto increment the version number so the MSBuild command used to build project A has /p:Version={version} where {version} is whatever version number determined by the build server.

Using the /p:Version={version} switch in MSBuild causes Nuget package A to have a dependency on package B of the exact same {version} instead of 2.0.0. This is very problematic, as we need to control the Nuget package dependency to package B on a specific version.

So here are all the things I've tried to get around this problem but all of them have their significant drawbacks:

  1. Instead of having project A referencing project B, reference prject B's NuGet package - package B.

    You lose project reference in this case, which can be a pain when you need to debug project A and B together.

  2. Bundle the assembly of project B into package A.

    So package A doesn't have a dependency on package B. However, because project B is also referenced by project C, D and E. If I do that to all of them, all packages will have the same project B assembly.

    When all packages are referenced by another project, they overwrite each other's assembly from project B, so some of them may have an older version of the assembly overwriting a newer version, causing unpredictable runtime problems.

  3. Have the build server update the Version element in project A's project file:

    <PropertyGroup>    
      <Version>1.2.3</Version>
    </PropertyGroup>
    

    then run MSBuild command without the /p:Version={version} switch.

    However, if the build server updates and commits the actual project file in our source control, this triggers the build server to build this project again, and it goes into an infinite loop.

This is where I'm at right now, trying to find a good solution to fulfil the following criteria if possible:

  1. The build server determines the version for both project A and B, and produces the corresponding Nuget packages with their version respectively.
  2. Package A should depend on the correct version of package B which is also built by the build server.
  3. Project A should reference project B as regular project reference.

Does anyone know if this is even possible?

Leon Zhou
  • 633
  • 6
  • 20
  • Did a simple test on my side and ran `msbuild.exe XXXXX /p:Version=XXXX`. I saw that projectA’s version was changed, but the projectB’s(checked the generated dll file of packageA) version was not changed. Not sure if some steps are missing, is it possible to share a reproducible simple test or some steps. – Tianyu Oct 08 '21 at 10:21
  • Hi @Tianyu, the problem is not MSBuild setting the assembly or file version, but setting the Nuget package dependency version. If you set project A to produce a Nuget package under the project's package settings, when you run `msbuild ProjectA.csproj /p:version=9.9.9`, it will produce a `ProjectA.9.9.9.nupkg`. Open it with [Nuget Package Explorer](https://github.com/NuGetPackageExplorer/NuGetPackageExplorer) and you will see it has a dependency of `ProjectB (>= 9.9.9)`. – Leon Zhou Oct 09 '21 at 11:26
  • Check the `Generate NuGet package on build` option and use MSBuild command line, open the generated `.nupkg` file with NuGet Package Explorer. I can see that the ProjectA's Version has changed to 9.9.9, but under `Dependencies:`, the dependency version is normal, on my side, still `XXXXX(>=1.0.0)` not `XXXXX(>=9.9.9)`. – Tianyu Oct 13 '21 at 13:31
  • @Tianyu it doesn't affect dependency version if the reference is not a "project reference". If you have project A referencing project B as a project reference, the dependency version of project B in the generated NuGet package will be `>=9.9.9` – Leon Zhou Oct 13 '21 at 21:57

1 Answers1

0

I was having the same issue today. Although this feels still feels kind of hacky, I think using MSBuild conditions is a somewhat decent solution.

You can pass the variable for your condition like so: -p:PipelineBuild=true, then replace the ProjectReference for a PackageReference when on the buildserver, using package versioning as usual.

<PropertyGroup>
    <PipelineBuild>false</PipelineBuild>
</PropertyGroup>

<Choose>
    <When Condition=" '$(PipelineBuild)'=='true' ">
        <ItemGroup>
            <PackageReference Include="ProjectA">
                <Version>[1.2.*,2.0.0)</Version>
            </PackageReference>
        </ItemGroup>
    </When>
    <Otherwise>
        <ItemGroup>
            <ProjectReference Include="..\ProjectA\ProjectA.csproj"/>
        </ItemGroup>
    </Otherwise>
</Choose>

Note: In Azure pipelines it is sufficient to add the PipelineBuild property to the pipline variables as long as <PipelineBuild>false</PipelineBuild> is not defined in the project file, if it is, you must pass the property within the MSBuild parameters as stated above.

cnork
  • 11
  • 3