Bridging On-Premise TFS and Microsoft Teams using Web Hooks and Node.js

At the beginning of this year Microsoft release their Slack competitor Microsoft Teams. After having recently migrated Exchange,Skype and SharePoint to Office 365 this seemed a natural next step for us.

My main use for Slack was as a central point for notifications from other applications such as StatusCake and Team Foundation Server. Unfortunately whilst the web hooks were compatible with Microsoft’s online offering of Visual Studio Team Services the output from an on-premise Team Foundation Server (in this case TFS 2015 Update 2) was different. This killed the usefulness of Teams for us completely.

Fast forward to now and I decided to revisit this issue and see if any progress had been made. Unfortunately Microsoft still does not have official support for this however I came across this post which gave me some hope I might be able to work around this.

Taking this code and making some modifications I was able to create a node.js based Windows service that translates the JSON from TFS and forwards it to Microsoft Teams in a format it understands.

Here’s how I did it.

*Disclaimer. I'm not a software developer and have never used node.js 
before now. There may be better ways to do what's below and I'd be happy to 
hear about them*

1. Create Channels in Microsoft Teams

The first thing you need to do is create the required channels in your Team. For my purposes I needed two channels “TFS New” and “TFS Updated” this allows me to mute TFS New when large operations are taking place (such as cloning a test plan with hundreds of tests).

2. Add Web Hook Connectors to Channels

Each channel requires a web hook creating in order to post data to. See here for information on how to do create a web hook.

Make sure to save the web hook URLs created.

3. Create the Application

I used Visual Studio 2017 for this with the option for Node.js development selected in the installer but you could also use VSCode or similar.

The first thing to do is create a new blank Node.js Web Application:

new-node-application

Open the server.js file (if not automatically opened), delete the contents and replace with the code below inserting the web hook URLs for each channel (excluding the first part of https://outlook.office.com) where it says WEBHOOKURL and the port you want to run the service on e.g. 8080 where it says TCPPORT.

var restify = require('restify');

//Set Webhooks for each channel here
var newChannel = "WEBHOOKURL";
var updateChannel = "WEBHOOKURL";

var server = restify.createServer();
server.listen(TCPPORT;, function () {
 console.log('%s listening at %s \r\n', server.name, server.url);
});

server.use(restify.bodyParser());

var client = restify.createJsonClient({
 url: "https://outlook.office.com",
 version: '*'
})

server.post('/api/notify/new', function (req, res) {
 console.log("*******New Request*******")
 console.log(JSON.stringify(req.body));
 console.log("\r\n");

 var detail = req.body.detailedMessage.markdown;

 var output = {};

 output["title"] = "Work Item Created";
 output["text"] = detail;

 console.log("******Request Response******");
 console.log(output);
 console.log("\r\n");
 client.post(newChannel, output);
 res.json(output);
});

server.post('/api/notify/updated', function (req, res) {
 console.log("*******New Request*******")
 console.log(JSON.stringify(req.body));
 console.log("\r\n");

 var detail = req.body.detailedMessage.markdown;

 var output = {};

 output["title"] = "Work Item Updated";
 output["text"] = detail;

 console.log("******Request Response******");
 console.log(output);
 console.log("\r\n");
 client.post(updateChannel, output);
 res.json(output);
});

This will give two endpoints to point TFS at:

http://x.x.x.x:port/api/notify/new
http://x.x.x.x:port/api/notify/updated

At this point if you attempt to debug your application in visual studio it will fail as you do not have the “restify” package installed.

To fix this open a node.js command prompt and change directory to the root of your project (where the server.js file lives) and type

npm install restify

followed by

npm init

Accepting all defaults for the above command.

Pressing F5 in Visual Studio or running the application manually by typing

node server.js

from your node command prompt should result in the service starting with no exceptions. You are now ready to test.

4. Test the Application

Create your web hooks in TFS to trigger on new and updated events. Ensure that when you create the web hook that you enter the URL and Port for your test environment where the application is currently running and the correct endpoint e.g:

http://192.168.1.100:8080/api/notify/new

See this guide for more details on creating service hooks in TFS.

Updating/creating a new TFS item or pressing the test button in the service hook should now update the appropriate Microsoft Teams channel:

new-teams-message-from-tfs

5. Install on a Server

The code will need to run as a service in order to process the requests from TFS 24/7 (the TFS server would be a good location for this but you can use any server that you can connect to from TFS).

  • Download and install Node.JS on the server from here.
  • Copy your project to a location on the server e.g. c:\tfs-teams
  • Follow the instructions here (modifying the code to have details of your server.js location/description etc) to run your application as a Windows service.

6. Update your TFS Service Hooks

You must remember to update your TFS service hooks to point at the location you have installed the service (or create new ones and disable the old ones until you need to use them for testing again).

You should now be up and running with your bridge between On-Premise TFS and Microsoft Teams.

If you want to take this further you can look at Office 365 Connectors API Reference to get ideas as to additional customisations you could make (red coloured cards for failed builds, green for successful?).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s