TeamCity Artifact Deployment
TeamCity is a powerful CI/CD tool, not only can it build and test your code, it can deploy it too. As someone who writes a few libraries, I need to be able to deploy them. Most of my Libraries are .NET based — framework and standard which means that I need to deploy to some sort of nuget server.
As my internal nuget server has decided to stop working for more than a few seconds at a time I decided to look for something else. So far this is mostly going well, I now have a nicer UI, the problem I have is that I need to get my nuget packages into it as part of the CI process. The old system was easy, I just needed to copy the nuget package to a local folder. Now that my nuget server is on a different box and needs a PUT operation to deploy I can’t do that.
All this leads me to Artifacts. These are a common concept in CI and as such are not hard to understand, they are basically any outputs from your CI process, this could be a package, or a zip file or a html report etc. What’s not so clear is how you know where these are and how to then use them. There is a lot of documentation out there but much of it seems to assume more prior knowledge than I had. What I am going to do here is explain how I create artifacts in my build and how I deploy them. I’m going to assume that you know how to create a build in TeamCity.
Firstly in the general settings for the build process, you need to set the artifacts path. As I’m working with .NET I know that my project can produce a package on build and it’s this artifact that we are interested in ie the .nupkg file. For dotnet core/standard this can be achieved with the following in your csproj file
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
You can also use the tick box in the project properties as shown. This means that whenever you build, a package will be created. In TeamCity I am running a Release build so the package will be created in
\bin\Release\
below my project.
Armed with this information we can update the General Settings for our TeamCity build. In the artifacts path we enter something like
+:src\bin\Release\*.nupkg => nuget/MyPackageLibrary
In this case the nuget package is in src\bin\Release\MyLibrary.<version>.nupkg. I used the wildcard so that any package stored here will be added to my artifacts, This is because I use GitVersion to generate version numbers so the package names will vary over time and if they are created I want them deployed by TeamCity
The output i.e. the package, will be put into a folder called nuget and it will be called MyPackageLibrary. You’re now ready to run your build as normal and produce your first artifact. If successful you will get something like this
Inside the nuget folder is where my artifact is stored.
The next step is that I need to deploy my artifact to my nuget server. The problem here is that my new nuget server is configured so that it won’t overwrite existing packages. This is a problem because it fails if there is already a package with the same name. This would mean that my build would fail even though it had actually worked.
To resolve this issue I setup a new deployment build. This needs to depend upon the original build and its artifact(s). I first setup a new build configuration, in my case I set this as a child of my original parent project
I also set it as a deployment project. This alters the fields available so that they are more appropriate for deployment.
We need to make this dependent on a snapshot of the parent project. on the dependencies menu just add a snapshot dependency, I used the following settings
The dependency is on my parent project which is set from a drop down. I chose to build on the same agent as I have others which may not always be suitable to use. This sets up a dependency chain, so if you run this build now it will run its dependents builds first.
Now I needed to setup an artifact dependency. To do this you add an artifact dependency and set the same Depend On value as you have above. Set get artifacts from to Build From the Same Chain. The artifact rules need to indicate where to find the artifacts. As you know from above we put these into a folder we called nuget. So in my case it looked like this.
nuget/MyPackageLibrary/MyLibrary.*.nupkg
I haven’t set a destination, this puts it into the checkout folder which is fine for my needs.
Now the dependencies are setup we can add the build steps as normal. I have one step which is a nuget push one. When I tried this the deployment still failed due to the existing package, so for the deployment package only I turned off one of build steps exited with an error (e.g non-zero exit code) from the failure section. This isn’t 100% perfect as it doesn’t cover failures for other reasons but for now it gets the job done. I can easily add deployment to other locations by just adding a new build step