Making SharpArch 2.0: Repositories, Build and Packaging

Following on from Geoff’s first post in this series, this post details the move from two repositories (Sharp-Architecture and Sharp-Architecture-Contrib) to the current set up, including how we’ve restructured the repositories themselves and included a common build system across everything.

TL;DR

We’ve moved all the SA repositories into a single GitHub organisation, separated samples into their own repositories, brought the repository structures in line with one another, and implemented a common build system shared by the solution in each repository.

Some Background

Until the end of last year, Sharp Arch consisted of two repositories. We had Sharp-Architecture, which contained SA itself and the Northwind sample app, and Sharp-Architecture-Contrib, which was pretty much what it said on the tin. The master versions of these repositories lived in Billy’s GitHub account.

When we started talking about Sharp Arch 2.0, Billy had already taken a step back from the project. Who Can Help Me? had been adopted as a second sample application (with the master version living in my GitHub account), and we had big plans for both Sharp Arch itself and the sample apps we provide for it. As a result, we made a few decisions:

We’d bring all of the Sharp Architecture repositories under one roof so that it was obvious what was “official” Sharp Arch and what wasn’t

We’d provide each sample app – including Northwind – in it’s own repository, rather than having a single massive repository containing SA core and all of it’s samples.

We’d adopt a common structure for all our repositories, so that people know what to expect when getting into each one.

We’d provide a common way of building all of the projects, so that we didn’t need something specific in each repository.

Step 1. Sharp Architecture organisation on GitHub

This was the easy bit; as you probably already know if you’re a Sharp Arch user, we’ve created a new GitHub organisation that our repositories can call home. It’s at https://github.com/sharparchitecture/ and at time of writing, contains the following repositories:

Sharp-ArchitectureThe core Sharp Arch projects. This currently has a master branch, which is the source of the current release (1.9.6), and a develop branch which contains the restructured work in progress version.

Sharp-Architecture-FeaturesAn all-new, 2.0 repository containing code for the different persistence options we’re providing for Sharp Arch 2.0. Because it’s new for 2.0, the master branch of this repository contains the code that’s aligned with the develop branch in the main Sharp-Architecture repo. Apologies if this is somewhat confusing.

Sharp-Architecture-ContribAs with the core repo, the master branch contains the source of the current release and the develop branch contains the Contrib project that will support SA 2.0.

Sharp-Architecture-BuildCommon build system for the Sharp Architecture solutions – see below for more information.

NorthwindThe original SA sample app. As before, master contains the code that goes along with the current SA release, and develop will be updated to use SA 2.0.

Who-Can-Help-MeSharp Arch’s second sample app. As before, master contains the code that goes along with the current SA release, and develop will be updated to use SA 2.0.

Sharp-Architecture-TemplateA new kid on the block, this will eventually contain the reference project structure that is used to generate the Templify package for SA. At the moment, our Templify package is built from the Northwind sample, but we are intending to change this as part of the 2.0 release.

Sharp-Architecture-CookbookAnother newbie – this is a new sample application that differs from Northwind and Who Can Help Me? in that it doesn’t intend to be a real world example of how to use SA to build an app. Instead, it will contain a series of examples of different things that can be done with SA. “Recipies” that you might find in the cookbook could include the different ways of setting up NHibernate (Automapping, Fluent and traditional HBM mapping), using SA with WCF, usage scenarios for LinqRepository and the Specification pattern and so on. Our hope is that over time, this will become the main reference for “how do I…” questions.

Step 2. Repository structure

We decided to standardise on the repository structure used in WCHM. At the top level, it contains the following folders:

Build Build scripts for the project – see below for more details

BuildSystemGit submodule used to pull the common build bits and pieces from Sharp-Architecture-Build.

CommonContains any common files used across multiple projects. In practice, this is normally a CommonAssemblyInfo.cs file, which holds the assembly attributes shared across all projects in solution, and an AssemblyVersion.cs which is automatically updated by the build process to ensure that assemblies get a version number that matches the TeamCity build number.

ReferencedAssembliesPretty much what it sounds like – external libraries that are used by the solution. These are normally organised into subfolders for each dependency, in order to make it crystal clear which assemblies are part of which dependency – for example, the NHibernate folder contains the core NHibernate.dll, Iesi.Collections and other supporting bits.

RequiredPackages Installers for anything you need to set up locally in order to use some or all of the solution. For example, it helps to have the T4Toolbox installed to work with the T4 templates that are currently part of SA, so the installer for this is included in the RequiredPackages folder of the Sharp-Architecture repository.

SolutionsHome for the projects that make up the solution. As you’d expect, each project is in it’s own subfolder, and the solution file sits here as well.

As mentioned above we felt that a common structure for the repositories is important. Not only does it mean that you know what to expect when getting into each repository, it also facilitates the next major step – the creation of a common build system for all of the projects.

Step 3. Common Build System

Up until 2.0, Sharp Arch has relied on a Nant build script for build and packaging. This has served well so far, but with the changes we’ve made in the way our repositories are structured, the time was right for a change.

The build system we now have consists of two parts:

A set of common MSBuild targets and tasks that encapsulate steps within the build process – for example, building a solution, running unit tests, or packaging source files. These files live in the Sharp-Architecture-Build repository, and each repository contains a submodule that pulls this into the BuildSystem folder.

A script that is specific to each repository and invokes the correct tasks from the common build project, with the correct parameters for the project. This script, along with some batch files that can be used to run it, exists in the Build folder of each repository.

Using this set up, and with the knowledge that each repository is structured in the same way, it’s simple to assemble the correct tasks to build and package any of the solutions from the Sharp Architecture repositories. For example, the process to build the Sharp Architecture core solution consists of the following steps:

Clean (remove any files from the Drops folder that are about to be recreated by this build)

Update the common assembly version number file that’s shared by all projects.

Build the solution

Run the MSpec unit tests

Merge the assemblies together

Package the assembly and source files.

If you compare this with the build process for Northwind – which, given it’s a sample app rather than the framework itself, you might expect to be somewhat different – you’ll see the following steps:

Clean

Update the common assembly version number file that’s shared by all projects.

Build the solution

Run the NUnit unit tests

Package the assembly and source files.

Clearly the bulk of the steps are actually the same as those required by the core Sharp Arch solution, hence the reason for encapsulating each of these steps in it’s own target so that it can be easily consumed as needed.

This system does, unfortunately, add some complexity to the process of getting source from GitHub and building locally. Once you’ve done a git clone of any of the repositories, it’s then necessary to run two additional commands against your clone.

git submodule init initialises the submodule

git submodule update updates the submodule with the files from the correct commit of the Sharp-Architecture-Build repository.

Anything that raises the barrier to getting started with Sharp Architecture is clearly not a good thing, so we’re still looking at ways in which this process can be improved.

Once the submodule is up to date, the files in the Build subfolder can then be used to build and package the solution. These scripts are also used for our CI builds, and when used with TeamCity they ensure that the assemblies created and packaged by each build are correctly version stamped with the build number, and that the packages created by the build process are published as build artefacts.

Next steps

As we continue working towards 2.0, it’s likely that we’ll evolve what I’ve described here but it’s unlikely to change radically. We’ll probably move to using NuGet instead of the old fashioned way of pulling in external dependencies, which may affect how we use the ReferencedAssemblies folders in each repository. And we’re also not entirely happy with the additional complexity that using Git Submodules adds to the mix, so we’re still thinking of ways to improve this. In addition, we’ll be making some additions to automatically create and publish the Templify and NuGet packages for Sharp Architecture.

As always, we welcome all suggestions, feedback and pull requests so please get involved and help us make Sharp Architecture something you want to use in your projects.