I have been spending most of my time splitting up a monolithic system into separately deployable NuGet packages. The system is monolithic in the sense that there are multiple domains that are deployed as independent WCF services, but all reference the same set of base projects. This means that all the source sits in the same repository. The first step has been to move these common libraries into NuGet packages served from a local network folder and referencing them in each of these solutions as a package rather than project.
- This is done fairly easily
- Create a new solution with a Class Library project in a new Git repo.
- Copy the classes from the old project to the new location and include in the project.
- Resolve any references - ReSharper for the system libs, NuGet restore for the others and then finally installing the newly created packages if the current package depends on it. (More on this later).
- Add a NuSpec file to the project.
- Build, package and push with NuGet.
Also, if you aren’t using ReSharper yet, just give it a try - it will open your eyes. Or as they mentioned in the Coding Blocks podcast: “Using ReSharper on legacy code is like walking into your hotel room with a black light” - it will show you how bad it really is.
Before we get to the actual implementation, just a quick overview of the Git-Flow branching model:
All development is done on feature branches cut from
develop and merged back in when done. When you have enough features for a release, you cut a short-lived
release branch from
develop. After this branch has been vetted, it will be merged into
develop (to ensure any fixes are also merged back into you development stream). When merging into
master, a tag with the new version number will be created. This will increment either the minor or major version number, depending on how big the release is. For hotfixes, you would branch from
master directly, fix the issue and then merge it back into
master as well as
develop. Every time you merge into
master, you update the version number and tag the source - this is the version that you want to use to stamp the releases with.
The command for the build & push with NuGet are (ignore the versioning and poking for further down):
This will result in the Class Library being packaged as a single NuGet package and pushed to the network share. This is the point where the PSake, GitFlow and Semantic Versions come in. When you use GitFlow, there is a very specific way to create new releases / hotfixes - this ties in perfectecly with SemVer. If you are just doing a minor feature release, you would increment the minor version number in the
<major>.<minor>.<hotfix> version of the release. Same with major / hotfix numbers. The catch is that you want to also stamp your package with this version and ultimately enforce this via the build server to prevent accidental releases of incorrect versions. Part of the GitFlow release / hotfix workflow is to specify the tag name. Using the git command
git describe --exact-match --abbrev=0 as part of the PSake function:
you are able to extract the last tag on a branch that matches the current commit hash. When done on the
master branch, you will always end up with the latest version - the only way for code to be merged into
master in GitFlow is via a feature or hotfix finish. The build process that builds the library has write-access to the network share, ensuring that only builds that were created via the build server are pushed to your private NuGet repository.
The last part of the puzzle is to also use this version number in the Nuspec file and the various assemblies. Here are the handy PowerShell functions that I have run into that will update the assemblies:
And the function to update the Nuspec xml file:
The actual xml update is done via:
Combining all of these together will allow you to release reliably versioned NuGet packages easily and the only dependency is PSake, PowerShell and git. This allows you to choose whatever flavour of build server you fancy. The obvious way to circumvent this is by committing directly to
master and creating a tag by hand, but that is a human issue that the angry dev mob will sort out with their pitchforks.