Quick TeamCity Build Status with AngularJS

So, this isn’t supposed to be the ultimate guide to AngularJS or anything like that – I’m not even using the latest version – this is just some notes on my return to The World of the View Model after a couple of years away from WPF. Yeah, that’s right, I just said WPF while talking about Javascript development. They may be different technologies from different eras: one may be the last hurrah of bloated fat-client development and the other may be the latest and greatest addition to the achingly-cool, tie dyed hemp tool belt of the Single Page App hipster, but under the hood they’re very very similar. Put that in your e-pipe and vape it, designer-bearded UX developers!

BuildStatus

Anyway, when I started, I knew nothing about SPA development. I’d last done JavaScript several years ago and never really used it as a real language. I still contend that JavaScript isn’t a real language (give me Scala or C# any day of the week) but you can’t ignore the fact that this is how user interfaces are developed these days… so, yeah, I started with a tutorial on YouTube.

I decided to do an Information Radiator to show build status from TeamCity on the web. Information Radiators are my passion – at least they’re one of the few passions I’m allowed to pursue at work – and we use Team City for all our continuous integration, release builds, automated tests and so on. Our old radiators are coded in WPF, which looks awesome on the big TVs dotted around the office, but doesn’t translate well for remote workers.

There is no sunshine and there are no rainbows in this article. I found javascript to be a hateful language, filled with boilerplate and confusion. Likewise, though TeamCity is doubtless the best enterprise CI platform on planet earth, the REST APIs are pretty painful to consume. With that in mind, let’s get into the weeds and see how this thing works…

Enable cross-site scripting (CORS) on your Team City server

You can’t hit a server from a web page unless that server is the server that served the web page you’re hitting the server with… unless of course you tell the server you want to hit that the web page you want to hit it with, served from a different server, is allowed to hit it. Got that? Thought so. This is all because of a really logical thing called “Cross Origin Resource Sharing”, which you can enable pretty easily in TeamCity as long as you have admin permissions.

Check out Administration -> Server Administration -> Diagnostics -> Internal Properties. From there you should be able to edit, or at least get the location of the internal.properties file. Weirdly, if the file doesn’t exist, there is no option to edit, so you have to go and create the file. Since my TeamCity server is running on a Windows box, I created the new file here:

C:\ProgramData\JetBrains\TeamCity\config\internal.properties

and added the following:

rest.cors.origins=*

You might want to be a little more selective on who you allow to access the server this way – I guess it depends on how secure your network is, how many clients access the dashboard and so on.

Tool Chain

This article is about AngularJS and it’s about TeamCity. It’s not about NPM or Bower or any of that nonsense. I’m not going to minify my code or use to crazy new-fangled pseudo-cosmic CSS. So setting up the build environment for me was pretty easy: create a folder, add a file called “index.html”, fire up the fantastic Fenix Web Server and configure it to serve up the folder we just created. Awesome.

If you’re already confused, or if you just want to play with the code, you can download the lot from GitHib: https://github.com/DanteLore/teamcity-status-with-angular

I promise to do my best

Hopefully you’ve watched the video I linked above, so you know the basics of an AngularJS app. If not, do so now. Then maybe Google around the subject of promises and http requests in AngularJS. Done that? OK, good.

Web requests take a while to run. In a normal app you might fetch them on another thread but not in JavaScript. JavaScript is all about callbacks. A Promise is basically a callback that promises to get called some time in the future. They are actually pretty cool, and they form the spinal column of the build status app. This is because the TeamCity API is so annoying. Let me explain why. In order to find out the status (OK or broken) and state (running, finished) of each build configuration you need to make roughly six trillion HTTP requests as follows:

  1. Fetch a list of the build configurations in the system. These are called “Build Types” in the API and have properties like “name”, “project” and “id”
  2. For each Build Type, make a REST request to get information on the latest running Build with a matching type ID. This will give you the “name”, “id” and “status” of the last finished build for the given Build Type.
  3. Fetch a list of the currently running builds.
  4. Use the list of finished builds and the list of running builds to create a set of status tiles (more on this later)
  5. Add the tiles to the angular $scope and let the UI render them

Here’s how that looks in code. Hopefully not too much more complicated than above!

buildFactory.getBuilds()
	.then(function(responses) {
		$scope.buildResponses = responses
			.filter(function(r) { return (r.status == 200 && r.data.build.length > 0)})
			.map(function(r){ return r.data.build[0] })
	})
	.then(buildFactory.getRunningBuilds)
	.then(function(data) {
		$scope.runningBuilds = data.data.build.map(function(row) { return row.buildTypeId })
	})
	.then(function() {
		$scope.builds = $scope.buildResponses.map(function(b) { return buildFactory.decodeBuild(b, $scope.runningBuilds); });
	})
	.then(function() {
		$scope.tiles = buildFactory.generateTiles($scope.builds)
	})
	.then(function() {
		$scope.statusVisible = false;
	});

Most of the REST access has been squirrelled away into a factory. And yes, our build server is called “tc” and guest access is allowed to the REST APIs and I have enabled CORS too… because sometimes productivity is more important than security!

angular.module('buildApp').factory('buildFactory', function($http) {
	var factory = {};
	  
	var getBuildTypes = function() {
		return $http.get('http://tc/guestAuth/app/rest/buildTypes?locator=start:0,count:100');
	};
	
	var getBuildStatus = function(id) {
		return $http.get('http://tc/guestAuth/app/rest/builds?locator=buildType:' + id + ',start:0,count:1&fields=build(id,status,state,buildType(name,id,projectName))');
	};
	
	factory.getRunningBuilds = function() {
		return $http.get('http://tc/guestAuth/app/rest/builds?locator=running:true');
	};

// etc

Grouping and Tiles

We have over 100 builds. Good teams have lots of builds. Not too many, just lots. Every product (basically every team) has CI builds, release/packaging builds, continuous deployment builds, continuous test builds, metrics builds… we have a lot of builds. Builds are good.

But a screen with 100+ builds on it means very little. This is an information radiator, not a formal report. So, I use a simple (but messy) algorithm to convert a big list of Builds into a smaller list of Tiles:

  1. Take the broken builds (hopefully not many) and turn each one into a Tile
  2. Take the successful builds and group them by “project” (basically the category, which is basically the team or product name)
  3. Turn each group of successful builds into a Tile, using the “project” as the tile name
  4. Mark any “running” build with a flag so we can give feedback in the UI

BuildStatus2

Displaying It

Not much very exciting here. I used Bootstrap, well, a derivative of Bootstrap to make the UI look nice. I bound some content to the View Model and that’s about it. Download the code and have a look if you like.

Here’s my index.html (which shows all the libraries I used):

<html ng-app="buildApp">
<head>
  <title>Build Status</title>
  
  <link href="https://bootswatch.com/cyborg/bootstrap.min.css" rel="stylesheet">
  <!--link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"-->
</head>

<body>
  <div ng-view>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.js"></script>
  <script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  <script src="utils.js"></script>
  <script src="app.js"></script>
  <script src="build-factory.js"></script>
</body>
</html>

Here’s the “view” HTML for the list (in “templates/list.html”). I love the Angular way of specifying Views and Controllers by the way. Note the cool animated CSS for the “in progress” icon.

<div>
  <style>
	.glyphicon-refresh-animate {
		-animation: spin 1s infinite linear;
		-webkit-animation: spin2 1s infinite linear;
	}

	@-webkit-keyframes spin2 {
		from { -webkit-transform: rotate(0deg);}
		to { -webkit-transform: rotate(360deg);}
	}

	@keyframes spin {
		from { transform: scale(1) rotate(0deg);}
		to { transform: scale(1) rotate(360deg);}
	}
  </style>
  
	<div class="page-header">
		<h1>Build Status <small>from TeamCity</small></h1>
	</div>
	  
    <div class="container-fluid">
		<div class="row">
    		<div class="col-md-3" ng-repeat="tile in tiles | orderBy:'status' | filter:nameFilter">
        		<div ng-class="getPanelClass(tile)">
               <h5><span ng-class="getGlyphClass(tile)" aria-hidden="true"></span>&nbsp;&nbsp;&nbsp;{{ tile.name | limitTo:32 }}{{tile.name.length > 32 ? '...' : ''}} &nbsp; {{ tile.buildCount > 0 ? '(' + tile.buildCount + ')' : ''}} </h5>
               <p class="panel-body">{{ tile.project }}</p>
              </div>
        	</div>
    	</div>
    </div>
	<br/><br/><br/><br/><br/><br/>
  
  <nav class="navbar navbar-default navbar-fixed-bottom">
  <div class="container-fluid">
    <p class="navbar-text navbar-left">
		<input type="text" ng-model="nameFilter"/>&nbsp;&nbsp;<span class="glyphicon glyphicon-filter" aria-hidden="true"></span>&nbsp;&nbsp;
		<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate" ng-hide="!statusVisible"></span>
	</p>
  </div>
</nav>
</div>

That’s about it!

I think I summarized how I feel about this project in the introduction. It looks cool and the MVC MVVM ViewModel vibe is a good one. The data binding is simple and works very well. All my gripes are with JavaScript as a language really. I want Linq-style methods and I want classes and objects with sensible scope. I want less syntactic nonsense, maybe the odd => every now and again. I think some or all of that is possible with libraries and new language specs… but I want it without any effort!

One thing I will say: that whole page is less than 300 lines of code. That’s pretty darned cool.

Feel free to download and use the app however you like – just bung in a link to this page!

BuildStatus

Super Quick Mini Quad

Super quick to build and super quick buzzing round the garden! Inspired by a recent video series by RC Model Reviews on YouTube I bought some bits and bobs from Hobby King to build my very own mini-quad.

2015-04-19 15.35.03

It’s been ages since I did anything in the garage, other than stir tins of Deep Bronze Green and repair punctures, so I was totally unable to wait for the second of my two parcels to arrive from the People’s Republic. Since I’d received everything except the frame within a couple of days and faced a two week wait for the frame itself, I knocked up a little quad frame from spare bits of carbon fibre and two meagre scraps of 6mm aluminium.

2015-04-19 15.35.11

It’s much smaller than my old quads. It was supposed to be a 250-class – so 250mm from motor to motor – but I chucked it all together free from the shackles of forethought and it ended up a little wide at the rear end. I drilled out, parted off and tapped four aluminium pillars, chopped and drilled some chunks of carbon fibre sheet and reinforced the motor arms with some square carbon tube with a balsa dowel insert.

One of the best things I did is make a power distribution board from a bit of veroboard. This makes wiring things up so much easier than faffing about trying to make a wiring loom. It also keeps the inside of the quad much tidier. I mounted it under the flight controller on some plastic standoffs which works very well.

2015-04-19 15.35.20

To fly it’s blooming amazing. I’ve only flown it round the (tiny) garden so far, watched by a curious three year old. The Naze32 board keeps things incredibly stable and the light frame and beefy little motors means it easily hovers at mid-stick. Leaving (hopefully) spare capacity for some FPV kit and a GoPro in future.

Huge thanks to Bruce from RC Model Reviews for making such a useful video series – and especially for recommending a list of cheap but super-effective components available for about £100.

The Chuffer

I just completed my second ever air engine: The Chuffer. With this project I decided that I’d go for complexity, rather than the simplistic approach I took when I built The Wobbler earlier this year.

The Chuffer is a twin-cylinder double acting engine – which means each of its two cylinders both push and pull the piston. This means it operates much more smoothly and can self-start as there’s always a piston on a power stroke, regardless of where the flywheel is.

Unlike its predecessor, the Chuffer has fixed cylinders and airflow is controlled by two spool valves, operated by eccentrics next to the flywheel via some pushrods and a hopelessly over-engineered lever mechanism.

And of course everything was made by yours truly, in the garage, from chunks of brass, steel and aluminium bar and flat stock I bought on eBay. Needless to say, I have learned a lot since I started the project this February!

What’s next? Well, maybe a Watt Governor or a little generator

Mapserver and Leaflet

Leaflet

Leaflet is a very simple but incredibly powerful Javascript mapping library that lets you add interactive maps to your website very easily. Try scrolling and zooming around this one:

For example, to add that map to this page, all I did was add the following code (after reading the Quick-Start Guide):

<div id="danMap" style="height: 200px;"></div>

<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>

<script type="text/javascript">
var map = L.map('danMap').setView([51.4, -1.25], 13);	
L.tileLayer('http://{s}.tiles.mapbox.com/v3/YOUR.MAP.KEY/{z}/{x}/{y}.png', 
{
  attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
  maxZoom: 18,
}).addTo(map);
</script>

You can add points, polygons and visualise all kinds of live data using a simple web service that returns some GeoJson data. It works like a charm on mobile devices too!

Why combine Leaflet with Mapserver?

I have a couple of use-cases that meant I needed to look at combining Leaflet with Mapserver. This turns out to be easy enough as Leaflet can hook up to any tile provider and Mapserver can be set up to serve images as a Web Map Service (WMS).

The first thing I wanted to do is serve up some map data when not connected to the internet. Imagine I am in the middle of nowhere, connected to the Raspberry Pi in the back of the Land Rover via WiFi to my phone or tablet. I have a GPS signal but I don’t have any connection to a map imagery server as there’s no mobile coverage. I need to use mapserver to render some local map data so I can see where I am. This use case has a boring work-related benefit too – it enables you to serve up maps in a web-based mapping application behind a strict corporate firewall.

The other use case is simple: raster data. Lots of the data we deal with where I work is served up as raster data by Mapserver. Imagine it as heat-maps of some KPI value layered on top of a street map.

Setting up Mapserver

There are a couple of things you need to do to get Mapserver to act as a WMS. The first is to add a projection and web metadata element to the root of the map file (as below). After a large amount of head-scratching, wailing and gnashing of teeth I found that the de-facto standard projection for all “internet” map data is EPSG 3857. Make sure you use that EPSG at the root of your map file.

PROJECTION
  "init=epsg:3857"
END
	
WEB
  METADATA
    "wms_title" "Dans Layers and Stuff"
    "wms_onlineresource" "http://192.168.2.164/cgi-bin/mapserv.exe?"
    "wms_enable_request" "*"
    "wms_srs" "EPSG:3857"
    "wms_feature_info_mime_type" "text/html"
    "wms_format" "image/png"
  END
END

The next thing to do is add some extra stuff to every layer in your map. You need to set the STATUS field to ‘on’; add a METADATA element and set the ‘wms_title’ to something sensible; and finally add a projection, specifying the projection the layer data is stored in. As I am using the OS VectorMap District dataset, which is on the OSGB projection I used EPSG 27700.

LAYER
  NAME         Woodland
  DATA         Woodland
  PROJECTION
    "init=epsg:27700"
  END
  METADATA
    "wms_title" "Woodland"
  END
  STATUS       on
  TYPE         POLYGON
  CLASS	
    STYLE
      COLOR 20 40 20
    END
  END
END 

Connecting it Together

You can then add a new layer to the Leaflet map, connected to your Mapserver. Here I’m using ms4w, the Windows version of Mapserver and hooking it up to a map file in my Dropbox folder. The map file I am using is the one I created for a previous post on mapserver.

L.tileLayer.wms("http://localhost:8001/cgi-bin/mapserv.exe?map=D:\\Dropbox\\Data\\Mapfiles\\leaflet.map", {
			layers: 'Roads,MotorwayJunctions',
			format: 'image/png',
			transparent: true,
			attribution: "Dan's Amazing Roads",
			maxZoom: 18,
			minZoom: 12,
		}).addTo(map);

Sadly I don’t have a mapserver instance on the internet, so all I can show here is a couple of screenshots. You’ll just have to take my word for it – it works brilliantly!

mapserverLeaflet2

mapserverLeaflet1

A sheared bolt and a mini adventure

On Thursday night last week my charge light didn’t go out. Since it was very wet I just assumed it was down to a slippy fan belt and decided to fix it at the weekend, provided the never-ending rains let up.
2014-02-16 15.02.07
After a huge fry-up at the farm, daughter and I set about fixing the problem – which turned out to be caused by the alternator completely snapping off! The 200Di conversion involved making a custom alternator bracket. Though the bracket itself is made from 10mm sheet steel welded to a chunky steel tube I made on the lathe, the weak spot is the M8 bolt which runs through it. This bolt had sheared off, leaving the alternator hanging loose. Luckily the fan belt didn’t fall off on the way home and I didn’t drive far enough to overheat the engine (the water pump must have stopped working as a result of the belt going slack).
2014-02-16 15.18.37
In the end I used a length of threaded bar instead of the stainless set screw that Emma is holding in the photo. Hopefully this will last a bit longer; stainless steel being notoriously brittle.
2014-02-16 16.39.27
I wasn’t allowed to start the engine “unless we’re going on a journey” so, once the fix was in, we headed up the road to Bucklebury Common. After the weeks of heavy rain and strong winds the common was pretty muddy and there were fallen trees and branches everywhere. I think the daughter enjoyed her introduction to Green Laning.
2014-02-16 16.39.30
In fact she took it so seriously she started compiling some pace notes!

The Wobbler

I made a Wobbler! A single acting, oscillating air engine, to be precise. I was inspired by the amazing Tubalcain, who’s YouTube channel has been the source of many top tips and the cause of many late nights. Though the design of the wobbler wasn’t new to me, the old Mamod steam engine I had when I was a kid used the same principle.

The wobbler is probably the simplest engine design there is. I tried to to a nice job of this one, though didn’t go overboard with the look of the thing – I don’t see the point of pretending it’s not made from some bits and bobs I has knocking about in the garage! Here are some photos:

2014-01-23 21.07.06

2014-01-23 22.04.21

2014-01-27 21.31.38

2014-01-27 22.03.00

2014-01-28 22.51.55

2014-01-29 22.14.48-1

2014-02-01 22.38.52

2014-02-01 22.39.06

Fixing the gear stick

For the last couple of weeks, gear changes in The Duke have been very hard work. The tiny pin which stops the stick spinning sheared off, adding a new element of drama to my commute.

image

The original pin had sheared and was stuck in the channel in the ball at the base of the stick.

image

So I had to strip the whole thing down.

image

The pin and the thread on the hole were totally ruined, so I had to think if something new.

image

I drilled out the hole

image

Then tapped it with an M8 thread. Much bigger and stronger than the old one.

image

Then turned down a set screw on the lathe

image

And heat treated it with case hardening compound, which will hopefully stop it getting squashed and bent.

image

I doubt there are many Land Rovers on the road with the original rubber blob on the base of the great stick. It’s meant to prevent vibrations but was totally worn away.

image

So I turned a replacement out of nylon and hammered it on.

image

At 19.3mm diameter is a snug fit on my spare gearbox and should help prevent rattles and make gears a bit easier to find.

image

All in all I’m very happy with my evening’s work. Just need the sun to come up so I can put it all back together again!