I had a strange problem earlier that I couldn't search for because I didn't know how to search for it!

Versions from the CI Server

In a devops environment, you tend to lose the idea of scheduled releases with version numbers agreed in advance and code tagged in-advance. That is just because in Devops, you want to do it many times a day and manually inputting versions would be a pain.

All CI tools have a concept of a build version and usually it is configurable to what you want.

For a simple web app, this is relatively easy to either inject directly into, say, web.config and displayed in the app footer for reference or otherwise passed onto your CD tool to inject it instead.

If you are building an individual project that will end up as a Nuget package, again, it is relatively easy to inject the build version into nuget pack and end up with a correctly versioned nuget package.

(Side note: there are lots of little annoyances with nuget pack that I will rant about later)

Dependent Projects

BUT what happens when you have projects that depend on other projects? How do you ensure that the build number generated in one build is available to the dependent build so that nuget can correctly specify that e.g. library B v2.0 depends on library A v1.5?

The main gripe I have with both nuget.exe and dotnet pack is that they are basically a bit crappy and only cover the main use-cases without providing the flexibility needed to be used in even a moderately complex configuration. They might support old csproj format and they might not, they might support project.json, they might not and also, in many cases, for features they don't support, there is no error or warning, they just might not work!

dotnet pack, for example, rather helpfully turns project references into nuget references so if we have A and B in a solution (B => A), it will translate this into nuget B depending on nuget A. Of course, this is helpful but it only has a master on-off switch. You can either have the versions baked into the csproj files (which are often not used in devops because it would require manually changing for every code change) or you can have no automatic references!

Nuget pack doesn't properly support the new csproj format and dotnet pack doesn't seem to work properly with nuspec files and also, this won't inject versions anyway unless you somehow manage to modify this file manually before calling pack but where will you get the versions from?

Injecting Version Numbers Back Into VCS?

I then wondered whether the build server could commit the versions injected by itself into the VCS to be used for any other builds but this looked flaky and could easily cause a circular dependency since the commit would trigger another build without filtering. It certainly didn't feel natural to do this.

In Team City, injecting a version into the csproj would get overwritten when the next project was built in the same directory even though the docs suggested it shouldn't clean the directory, it was doing a git reset hard! Everything ends up dependent on v1.0.0 of everything else, which is useless for packaging.

Build Everything Together?

I tried to work out if a single build project could deploy all of our 5 libraries in one go but then that means every change causes an upversion of every library without some cunning or hacky fix.

Using Build Artifacts

Since I was already injecting build versions into the csproj files using Powershell before running dotnet pack, I realised that if I used these files as the project artifacts, I could then set them up as dependencies into the dependent builds and simply overwrite the VCS version of the file with the correctly versioned csproj from the build artifact and it would all work!

It did but it didn't feel quite correct since the version numbers should be passable to dependent projects.

Maybe there is an easier way but like I said, if you can't find a phrase to search for, how do you search for it?