Deploying An ASP.NET Core Site: You're Still Doing It Wrong - Part 5 - Why Stop Now
This day and age, predictability and reliability are two of the most important words when it comes deployments. In this series, I am going to talk about how to add both predictability and reliability to your ASP.NET Core Continuous Integration pipeline using TeamCity and Octopus Deploy.
We sure came a long way since part 1 of this series. Since we started we manged to accomplish...
- Automating a trigger to build on a code push to our GitHub repository.
- Automating a build chain that will "restore", "build" and "publish" our application in TeamCity.
- Automating a versioning of our build.
- Automating a push of our build to Octopus Deploy.
- Automating configuration of a build.
- Automating a deployment to multiple targets
More importantly, through automation, we have introduced predictability and reliability by removing the human variable from the process. Yes, we are finally doing it right!
But why stop now. There is still so much more we can accomplish with our shiny new Continuous Integration pipeline. Following, I will touch on a few additional steps you might want to consider adding.
In this series, we focused on building and publishing our ASP.NET Core application inside TeamCity. But that story is incomplete when talking about most modern web apps. In most cases, there are additonal steps needed to get your front-end assets in a deployable state. For example, with Pioneer Code I have to transpile my TypeScript, build my Sass and bundle and minify it all together in a nice small package.
Modern tooling for front-end builds, regardless of the steps you take, are more often than not command line driven. That being said, we can utilize the Command Line Runner Type inside of TeamCity and add the necessary steps needed to our Build Steps.
Depending on your needs you will have a series of steps that look like this.
As you can see, there is really nothing going on special here. I am running native commands against a cli to step through my build process. With the addition of my front-end steps, my Build Step(s) look like the following.
You are also going to want to setup Failure Conditions that correspond to your new command line build steps. Without these, we will not have a way to terminate a build on a command line failure and report back some meaningful message to the user. In your project settings section of your project, head to the Failure Conditions page and add a new "failure condition". In this section, you will add a string that matches a failure inside your build log. For example, I added a generic "exited with code 0" to catch all errors that I might miss. I then added a meaningful message to report back to the user. Of which, resulted in the following.
Wait, What About Our Database?
When it comes to databases and Continuous Integration, there is nothing stopping us from making the process just as effective as we have done with our web-application. How we go about accomplishing this usually falls in one of two camps. You either take the code-first approach and generate migrations based off of model/entity updates, typically done with an ORM like Entity Framework, or you write out scripts. Both when deployed are tracked in a state based table that identifies what script or migration was last run against that database.
At my job, we like to write scripts to track our database changes. This allows for those who are not familiar with our .NET code, such as a database administrator, to step in and contribute. To accomplish this we utilize a product called DbUp. On deployment, DbUp determines what scripts have been ran and what need to be run in order to get our databases to an updated state.
There is a small amount of setup that is needed to facilitate DbUp, of which is documented at DbUp Documentation. Once setup, integration into your CI pipeline is as simple as adding a Deployment Process step to your Octopus Deploy project. This step would be responsible for running a powershell command that calls the DbUp executable hosted in your project and DbUp will do the rest so long as your connection string is applied through configuration.
& .\Pioneer.Blog.Databse.exe | Write-Host
ORM: Migrations & Entity Framework
Code first migrations are a great tool for developers to utilize. They allow us to stand-up a database and make changes at a really quick clip. That being said, my approach to using them is mainly for development. Once my database is in a state that is steady enough to consider deployable, I tend to switch to scripting. That being said, there is no reason why you would not be able to run migrations from a command-line step in your Deployment Process.
Let me say this and say it loud, running automated tests during your build process is something that we all should strive for. Doing so culminates in a build that is, by a large factor, more reliable then a build that does not have tests ran against it. This will have a positive impact that will trickle down through your entire development process.
xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. xUnit.net
xUnit.net is a widely used testing tool and my primary framework when it comes to testing in .NET. To get up and running in TeamCity, you first need to install the xUnit.net plugin. After the plugin is installed, you can add a build step to your Project and set it to the Runner Type xUnit. From there you have a few configuration options to setup.
Visual Studio Tests
For those who prefer using the MSTest runner, TeamCity has a built-in plugin available for you.
Build Status On GitHub
TeamCity now ships with a Build Feature called Commit Status Publisher. This Build Feature allows TeamCity to automatically attach builds statues to an external system such as GitHub. To get started, head to the Build Features section of your project and select the Select the "Add Build Feature" option.
Here you will be given an option to select the external system you want to tie into. Obviously, we will be selecting GitHub for our integration. Leave the GitHub URL as is, unless you are hooking up to a deployment of GitHub Enterprise.
You can authenticate with GitHub with your username and password, or by creating a personal access token. I opted to use a token so I don't have to worry about remembering to update my password in TeamCity every time I change it.
Once you have your Build Feature configured and you have tested your connection, hit save and your Build Feature will be displayed as follows.
That's it. The next time you fire off a build from TeamCity, you will see build status indications inside of GitHub like the following.
That Is A Wrap
Hopefully I have demonstrated some of the power that is associated with having an Continuous Integration pipeline at your disposal and possibilities moving forward. Each situation is going to be unique to your application and needs but the concepts outlined in this series will still hold true. As always, if you have any question or comments please feel free to leave them in the comments section below..