Nuget Sitecore Habitat

Sitecore Habitat is an open source library that provides over 50 modules for Sitecore that can be used within any project. This article outlines one way of building Sitecore Habitat project into Nuget Packages using TeamCity.

Note: It is assumed that:

  1. You already have configured TeamCity Server and at least one TeamCity Build Agent.
  2. You have already set NodeJS plugin in TeamCity
  3. The Build Agents have Visual Studio 2015 Community (or licensed version) installed (Downloadable from: https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx)
  4. The Build Agents have NodeJS installed globally (Downloaded from: https://nodejs.org/en/download/)
  5. You have read the previous article, Nuget Package Create through Powershell

Step 1: Create TeamCity Project

Go to the Projects section under Administration and create a new Project. Type a significant name for the project. In this article case, the Project is named: Habitat Module Builder.

TeamCity Project Create

TeamCity Project Create

Step 2: Setup VCS Root

When the Create button is pressed a screen with the project configuration is shown. Select the VCS Roots tab and Create a VCS root pointing to the Habitat Github URL.

TeamCity VCS Root Create Option

TeamCity VCS Root Create Option

VCS Git setup

VCS Git setup

Note: Test the connection with Github before proceeding with Creating the VCS Root to ensure the settings are correct.

Step 3: Setting up Project Settings

Navigate to the General Settings tab to start building the configuration.

Create Build Configuration option in General Settings

Create Build Configuration option in General Settings

Step 4: Set the Configuration name

For the purpose of this article the configuration is named: “Habitat Nuget Packages Builder”

Setting Configuration Name

Setting Configuration Name

Step 5: Attach VCS Root to Configuration

Attach VCS Root Option

Attach VCS Root Option

Selecting VCS Root

Selecting VCS Root

Note: Since the VCS Root was created earlier in the Attach VCS Root screen use the Attach existing option dropdown and press the Attach button.

Note: This step will trigger a search for build steps in the repository. The step can be cancelled as the build steps will be defined manually later on.

Step 6: Set up VCS Triggers

Add new Trigger option

Add new Trigger option

Setting up the Trigger option

Setting up the Trigger option

Note: The options in orange are shown by clicking the “Show advanced options” link.

Step 7: Start setting up the Build Steps

The Build Steps screen provides two options: Add build step and Auto-detect build steps. We will make use of the manual Build step, since the project cannot be triggered through msbuild alone.

Add Build step

Add Build step

Step 8: Install NodeJS libraries on the Build Agent for the project

Configuration for automatic install of NodeJS libraries on the Build Agent at Project levell

Configuration for automatic install of NodeJS libraries on the Build Agent at Project level

Step 9: Make sure to have Sitecore DLLs somewhere where the Build Agents can find them

The Habitat project comes with a Gulp script that copies over the Sitecore Libraries to all projects. In order for the build to succeed it is important that Gulp script finds the Sitecore Libraries to copy them over. For this article, we will be assuming that the DLLs are located in the location C:\Sitecore\Lib.

Step 10: Configure Gulp

Gulp uses the file gulp-config.js as a configuration. Using Powershell scripting the gulp-config.js file is manipulated to point to the Build Agent Sitecore library files.

Powershell script setup for Gulp Configuration manipulation

Powershell script setup for Gulp Configuration manipulation

  1. (Get-Content %system.teamcity.build.checkoutDir%\gulp-config.js).Replace("C:\\websites\\Habitat.local\\Website\\bin", "C:\\Sitecore\Lib") | Set-Content %system.teamcity.build.checkoutDir%\gulp-config.js

Code 1: Powershell Script for Gulp Configuration manipulation

Step 11: Run Gulp Command to Copy Sitecore Libraries

Gulp setup to copy Sitecore Libraries

Gulp setup to copy Sitecore Libraries

Step 12: Restore Nuget Packages

Restore Nuget Packages Step

Restore Nuget Packages Step

Step 13: Build The solution

Build the solution with Visual Studio

Build the solution with Visual Studio

Step 14: Create NuGet Specifications for all projects

Powershell script setup for Nuspec creation

Powershell script setup for Nuspec creation

  1. # Add System.Web to HTML encode copyright string
  2. Add-Type -AssemblyName System.Web
  3.  
  4. # Storing the Powershell execution location to restore path at the end
  5. $runLocation = $PSScriptRoot
  6.  
  7. get-childitem "%system.teamcity.build.checkoutDir%\src" -recurse | where {$_.extension -match ".\w\wproj"} | % {
  8.   if (-Not ($_.Directory -match "Tests$" -Or $_.Name -match "Website|Demo")) {
  9.     Set-Location $_.Directory
  10.     %teamcity.agent.tools.dir%\NuGet.CommandLine.DEFAULT\tools\NuGet.exe spec -f
  11.     $assemblyName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
  12.     $nuspec = "$assemblyName.nuspec"
  13.     [xml]$nuspecXml = (Get-Content $nuspec)
  14.     $licenseUrlNode = $nuspecXml.SelectSingleNode("//licenseUrl")
  15.     $licenseUrlNode.ParentNode.RemoveChild($licenseUrlNode)
  16.     $iconUrlNode = $nuspecXml.SelectSingleNode("//iconUrl")
  17.     $iconUrlNode.ParentNode.RemoveChild($iconUrlNode)
  18.     $releaseNotesNode = $nuspecXml.SelectSingleNode("//releaseNotes")
  19.     $releaseNotesNode.ParentNode.RemoveChild($releaseNotesNode)
  20.     $tagsNode = $nuspecXml.SelectSingleNode("//tags")
  21.     $tagsNode.ParentNode.RemoveChild($tagsNode)
  22.     $projectUrlNode = $nuspecXml.SelectSingleNode("//projectUrl")
  23.     $projectUrlNode.InnerText = "https://github.com/Sitecore/Habitat"
  24.     if (Test-Path ..\serialization) {
  25.       $filesNode = $nuspecXml.CreateNode("element", "files", "")
  26.       $fileNode = $nuspecXml.CreateNode("element", "file", "")
  27.       $fileSrcAttribute = $nuspecXml.CreateAttribute("src")
  28.       $fileSrcAttribute.Value = "..\serialization\**\*"
  29.       $fileNode.SetAttributeNode($fileSrcAttribute)
  30.       $fileSrcAttribute = $nuspecXml.CreateAttribute("target")
  31.       $fileSrcAttribute.Value = "content\serialization\$assemblyName"
  32.       $fileNode.SetAttributeNode($fileSrcAttribute)
  33.       $filesNode.AppendChild($fileNode)
  34.       $nuspecXml.LastChild.AppendChild($filesNode)
  35.     }
  36.  
  37.     $assemblyInfo = (Get-Content Properties\AssemblyInfo.cs)
  38.     $copyright = ($assemblyInfo -match 'AssemblyCopyright\(".*"\)')
  39.     $copyright = $copyright -split ('"')
  40.     $copyright = $copyright[1]
  41.  
  42.     $copyrightNode = $nuspecXml.SelectSingleNode("//copyright")
  43.     $copyrightNode.InnerText = [System.Web.HttpUtility]::HtmlEncode($copyright)
  44.  
  45.     $author = ($assemblyInfo -match 'AssemblyCompany\(".*"\)')
  46.     $author = $author -split ('"')
  47.     $author = $author[1]
  48.  
  49.     If ($author -eq "") {
  50.       $authorNode = $nuspecXml.SelectSingleNode("//authors")
  51.       $authorNode.InnerText = "Habitat Community"
  52.  
  53.       $ownersNode = $nuspecXml.SelectSingleNode("//owners")
  54.       $ownersNode.InnerText = "Habitat Community"
  55.     }
  56.  
  57.     $description = ($assemblyInfo -match 'AssemblyDescription\(".*"\)')
  58.     $description = $description -split ('"')
  59.     $description = $description[1]
  60.  
  61.     If ($description -eq "") {
  62.       $descriptionNode = $nuspecXml.SelectSingleNode("//description")
  63.       $descriptionNode.InnerText = "Habitat Module"
  64.     }
  65.  
  66.     $nuspecXml.Save($_.Directory.FullName + "\" + $nuspec)
  67.   }
  68. }
  69.  
  70. Set-Location $runLocation

Code 2: Powershell script for Nuspec creation

Step 15: Build NuGet packages

NuGet Package Step

NuGet Package Step

Step 16: Publish NuGet packages to local Nuget Server

Note: In this article it assumed that the local Nuget Server is accessed through the URL http://nuget.dev. Please ensure that you change this to your actual local Nuget Server.

Publish Nuget Packages Step

Publish Nuget Packages Step

Note: You need to open the advanced options to set the Nuget Server location.

Complete Project configuration look

Complete Project configuration look

Step 17: Verify that the build ran successfully

Build Result is Green

Build Result is Green

NuGet Server showing the Packages (XML feed)

NuGet Server showing the Packages (XML feed)

Sharing other consideration

Consideration 1: Clean Policy for Git

Due to the manipulations that are performed during the build it is ideal to clean the checked out code with each git pull. To do this, go in VCS Root edit screen. Click the ‘Show advanced options’ and set the Clean Policy option to Always.

Git Checkout Clean Policy

Git Checkout Clean Policy

Consideration 2: Test at each step

When building large configurations like this one, it is important that to test at each step to ensure that things work as expected. Especially where Powershell scripts are used as locations, especially for the NuGet.exe file, might change based on the build agent configuration.