Visual Studio Team Services Continuous Integration (CI) and Angular 4 AOT

Background

With much enthusiasm and eagerness, we have begun development on a new green field project for a client offering the opportunity to use the latest Angular framework (Version 4 at the time of this article) for front end development. Anytime a new, vastly improved framework becomes available and fits a new Enterprise project, most technologists will get a warm and fuzzy feeling.  Long story short, I am enjoying my current project immensely.

The development tools/technologies of choice for this client are primarily from the .Net Stack (Visual Studio 2017, C#, ASP.net 4.x, SQL Server, etc.) with Angular 1.x. some MongoDB, etc used in various capacities. The primary infrastructure available at this client for development work is made up of an onsite Team Foundation Server 2015 installation, Windows Server 2012 R2 VMs, SQL Server 12.x.

The project in this case study was started as an ASP.Net MVC/WebAPI solution but Angular 4 was added to the mix following the Visual Studio 2015 within an ASP.NET 4.x project cookbook at https://angular.io/docs/ts/latest/cookbook/visual-studio-2015.htmlAOT compilation was set up following the AOT compiler cookbook at https://angular.io/docs/ts/latest/cookbook/aot-compiler.html.

Goal(s)

Setup a Continuous Integration (CI) environment for our new project and leverage cloud based tools when available per executive team mandate. Some of the primary considerations for choosing Team Services over TFS 2015 onsite are:

  • Solve the issues we were encountering related to AOT compilation which are detailed at http://spartansoft.net/visual-studio-2017-npm-integration-continuous-integration/.
  • Access to the latest and greatest features.
  • The client’s desire to begin phasing out as much local infrastructure as possible by moving applications/VMs to the cloud. Team Services Cloud vs. OnPremise TFS.  Another example was the client’s move from internally hosted Exchange to Office 365.
  • No initial hosting/licensing expenditures given current MSDN subscriptions.
  • Green Field project so no effort related to migrating from OnPremise to Cloud. At some point the decision may be made to migrate the large existing codebase currently hosted locally in TFS 2015 but that will be another article and adventure.
  • Given the possibility of scaling the development team by offshoring some generic development tasks, continuous integration is critical.

Use Case

Set up CI with the following workflow

  • On every check-in to source control, make sure the project compiles and builds successfully.
  • On every check-in to source control, make sure all unit tests pass.
  • If either the build and/or Unit tests fail, notify the entire development team via email.
  • The notification should provide insight into what the actual reason is for the failure.

Define the build process

Some tweaks were required to get the base code in a state that could be successfully built using Team Services. Hopefully documenting the steps and the hurdles encountered can help others efficiently set up their own CI environments.

Just be forewarned, you will develop an aversion to the color red as you work through getting your build setup, and will celebrate the arrival of anything in green! Let the fun begin…

Creating a New Build

Once logged into Team Services, click on Build & Release in the top navigation bar.

Select Build & Release
Select Build & Release

Create a new Build by clicking the New button on upper far right.

Select New Project
Select New Project

Next you will be presented with a list of templates. For this project I am going to select ASP.Net (Preview) and click Apply.  Selecting this template will create a new build definition with default tasks added as listed below.  You will need to provide the build with a friendly name, and the path to your solution or packages.config file. We will keep the default Artifact Name for the time being.

Select a Build template
Select a Build template

Set Build Process Options

For the initial setup, we will keep the defaults under options and variables other than the following two:

  • Click on Options, change the Default agent queue from Hosted to Hosted VS2017.
  • Click on Variables, change the Build Configuration to the one you are targeting for this build.

Get Sources Task Setup

The defaults for this task are sufficient for this build task. As shown, the code can originate from various sources, while ours is hosted in Team Foundation Version Control.

Get Source Task
Get Sources Task

NPM Install Task Setup

Click the Add Task button found below the list of tasks.

Add new Build Task
Add new Build Task

Then select the npm task and click add.

Add new npm Task
Add new npm Task

The default values are sufficient for this task. Specify the path to the root of your website project containing your package.json file.

npm Install Task
npm Install Task

Nuget Restore Task

Setting up this task was more challenging than anticipated.  After working with version 1 of the task without much success, I settled on version 0 with the following properties using NuGet Version 4:

Nuget Restore Task
Nuget Restore Task

Nuget Restore Task Hurdles

The initial run of the Nuget restore task resulted in the following error.

d:\a\_tasks\NuGetInstaller_333b11bd-d341-40d9-afcf-b32d5ce6f23b\0.2.31\node_modules\nuget-task-common\NuGet\4.0.0\NuGet.exe failed with return code: 1 Packages failed to install

Although there are many different configurations related to the Nuget Installer Task, the solution that worked for our configuration using Version 0 of the task was adding the Package source https://api.nuget.org/v3/index.json to NuGet.config file.

Specify Nuget PackageSource

Angular AOT Generation Related Tasks

As mentioned earlier in this post, we have leveraged the Visual Studio Angular AOT compilation approach following the cookbook at https://angular.io/docs/ts/latest/cookbook/aot-compiler.html. Two npm commands were added to our package.json file as follows:

AOT npm commands
AOT npm commands

We currently run those from the Task Runner in Visual Studio, but at this point, we want to add them to our Build pipeline in Team Services. This is done by adding two additional npm tasks defined as follows:

AOT Build Task

Angular AOT Build Task
Angular AOT Build Task

AOT Generation Tasks hurdles

On the initial run, the AOT Build Task failed with errors below related to the Angular Material module we had added to our project.

/node_modules/@angular/material/typings/checkbox/checkbox.d.ts:43:41: Type ‘(new (…args: any[]) => CanDisable) & typeof MdCheckboxBase’ is not a constructor function type.

/node_modules/@angular/material/typings/radio/radio.d.ts:24:22: Class ‘MdRadioGroup’ incorrectly implements interface ‘CanDisable’.

The errors were related to TypeScript needing to be updated. This was accomplished by bumping the version in packages.json file under devDependencies from 2.1.0 to 2.3.3 matching the version we were running locally.

Rollup Task

AOT Rollup Task
AOT Rollup Task

Rollup Task Hurdles

Prior to moving to Team Services, we managed our builds using MSBuild scripts coupled with Publish Profiled (pubxml).  Build generated assets, node modules or Nuget packages are never added to source control. Using our local build scripts, I noticed although the build.JS file generated by the Rollup command was contained within the web project folder structure, it was not being deployed upon publication.  To solve this issue, we modified our publish profile to copy the generated folder to the output.

For our Angular 4 Team Services AOT build, I could have created a new Copy File Task but opted for creating a wpp.targets file with the same code used in the pubxml which runs locally.  The file should be named [Insert your ASP.Net web Project Name here please].wpp.targets with the following markup, and saved to the root of your website project. This file basically tells the build process to copy the dist folder and all its contents. In this case, the rollup step’s build.js gnerated file to the output folder of the build.

Copy files for deployment
Copy files for deployment

or for copy and paste purposes

<?xml version=”1.0″ encoding=”utf-8″ ?>
<Project ToolsVersion=”4.0″ xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>
<Target Name=”AddAngularAOTJSFile”
BeforeTargets=”CopyAllFilesToSingleFolderForPackage;CopyAllFilesToSingleFolderForMsdeploy”>
<Message Text=”Adding Aot Dist files to deploy” Importance=”high”/>
<ItemGroup>
<CustomFilesToInclude Include=”.\src\dist\**\*.*” />
<FilesForPackagingFromProject Include=”%(CustomFilesToInclude.Identity)”>
<DestinationRelativePath>.\src\dist\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>

Visual Studio Build Task

The only item changed from the defaults was the Visual Studio version which I changed to 2017,

Visual Studio Build Task
Visual Studio Build Task

Visual Studio Build Task hurdles

This task initially failed with the error :

Error : This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ..\.nuget\NuGet.targets.

After opening the web project file in NotePad, I found Nuget.target references below which I removed from all projects contained in the solution.
<Import Project="..\.nuget\NuGet.targets" Condition="Exists('..\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\.nuget\NuGet.targets'))" />
</Target>

I also removed NuGet.exe and NuGet.targets files from the solution.

Remove Nuget.exe and NuGet.Targets
Remove Nuget.exe and NuGet.Targets

The original NuGet.Config was also updated to include packages source as described above.

Remaining Tasks (Test Assemblies, Publish symbols path, and Publish Artifacts)

The defaults were sufficient for our needs for the Test Assemblies, Publish symbols path and Publish Artifacts tasks.  I may dig into some of those tasks as we continue with the project and begin setting up deployment and Continuous Delivery capabilities.  We also will be adding some Jasmine Unit Tests that would need to be added to the process.  I will either include the additional information in the upcoming Deployment and CD post, or add details to this existing post once the above needs are included in an upcoming sprint.

Completed Build Task Pipeline

After completing the all the previous steps, you should be left with something resembling the below Build Process.  Order is important..

Completed Build Process Tasks
Completed Build Process Tasks

 

Builds Dashboard

There are various places you can queue up a build to be run, one being the Build Dashboard. Selecting Queue new build will add the build to be processed by the build agent when one is available.  Your reward for all your time and effort is a lovely green check-mark followed by the wonderful word succeeded.  May not seem like much of a reward but after setting up your first build with a few challenges thrown your way and numerous build failures you will understand. Hopefully this post will help you reap the rewards of green as quickly as possible!

Build Dashboard

Build Dashboard

Define Workflow

As specified in out use case, we want to run a build on every check-in. This type of workflow can be setup by enabling the continuous integration trigger under the Triggers section accessed from editing a build.  There are other options such as scheduled builds and gated check-ins which are not currently of interest for our needs, but powerful just the same.

Enable Continuous Integration
Enable Continuous Integration

An example of a failed build email notification is as follows:

Build Failure Notification
Build Failure Notification

Thoughts/Next Steps

Mission accomplished!!! Continuous integration for this project has now been implemented, is working as desired, and was fairly easy to setup.  I am extremely impressed with the tools available using Visual Studio Team Services, and would love to migrate the rest of the client’s projects to this environment.  A TFS migration to Team Services would certainly require a cost/benefit analysis due to significant amount of code we have written for this particular client. However, for a Green Field project, it is a absolute no brainer IMO.  Two Thumbs up for Visual Studio Team Services!

The next steps would include deploying the code to Azure and/or the client’s onsite IIS load balanced QA Environment, as well as setting up Continuous Delivery based on what we have done thus far.  Happy Integrating!



2 Comments

Leave a Reply