Wednesday, September 14, 2016

VSTS Extension Work Item Limits

An error was recently pointed out on one of the extension that I’ve been working on as part of the ALM Rangers.

Looking at the browser logs we noticed something like this:
"An undefined error occurred while attempting to connect to the server. Status code 0: error."


Very descriptive, right?!
It turns out that the root of the error lies in the fact that we were hitting limits with regards to work item queries. It looks like VSTS/TFS API only allows us to "read" in the region of about 300 work items at a go. It appears that there are teams out there that need up to a few thousand at a go.

How did I fix this? A great little JavaScript library called Q.
It was a fairly simple change as we all use the promise pattern for asynchronous calls to the services. Q is a chaining library that allows me to create a bunch of promises and wait for them to complete execution.

Practically this means breaking the list of work item id’s that I need into smaller chunks and then fetching these chunks. We could have simply written a recursive loop that would perform the same, but I’m lazy.

The code change looked like this:

From simply calling the API with all the work item id’s:

client.getWorkItems(backlogIds, null, asOfDate, WorkItemContracts.WorkItemExpand.Relations).then(backlogWorkItems => {


var loadSpecs = new Array<IPromise<any>>();
var spliceSize = 100;
var backlogSection = backlog.splice(0, spliceSize);

while (backlogSection.length > 0) {
   loadSpecs.push(this.GetWorkItemDetails(backlogSection, asOfDate));
   var backlogSection = backlog.splice(0, spliceSize);

Q.all(loadSpecs).done(all => {
  //combine “all” the results into one

The GetWorkItemDetails method simple returns the promise from client.getWorkItems:

public GetWorkItemDetails(backlogItems: number[], asOf: Date): IPromise<any> {
   var client = WorkItemRestClient.getClient();
   var defer = $.Deferred<any>();
   client.getWorkItems(backlogItems, null, asOf,
        .then(backlogWorkItems =>   
   return defer;

This may not be the neatest, and please do not criticize my Javascript skills (I’m not a JS developer Surprised smile ), but it works and was a lot quicker to “fix” than expected.

For the full source code feel free to go and have a look at the github repo, in fact why not join in and make it better ! Open-mouthed smile

Wednesday, April 13, 2016

Upload Custom Build Tasks On-prem TFS 2015 Update 2

One of the great features that TFS 2015 Update 2 brings to the party is the ability to add extensions and custom build tasks.

I was sorely missing the SQL dacpac deployment task that has been available on VSTS for a while, so I decided to upload it myself.

First of all, all the source for the VSTS / TFS build tasks is actually available. If you have not already, head over to Microsoft's GIT repository and take a look for yourself. You may notice that the SqlServerDacpacDeployment is just sitting there, ripe for the picking…

To get the build tasks uploaded to your on-prem is not as straight forward as it would seem though. First of all, you need the TFS Cross Platform Command Line (tfx) command line utility to upload the build tasks. It in turn requires NodeJS. Once all that is installed you can start uploading your extensions and build tasks… well almost.

Tfx does not yet support integrated authentication, and on-prem versions of TFS do not yet have "Personal Access tokens" or PATs. Tfx does however support basic authentication, which means we need to tweak our TFS instance a bit to be able to upload our own tasks.

TFS Basic_thumb[1]

We need to get onto the TFS server and open up IIS. Select the "tfs" application under the Team Foundation Server site and enable basic authentication.

Once you have done that you are ready to upload your tasks. After downloading the task repo from Microsoft I simply opened up a command prompt and executed the following command :
tfx build tasks upload --service-url http://<<server>>:8080/tfs --auth-type basic --username <<username>> --password <<password>> --task-path .\SqlServerDacpacDeployment

Interestingly enough that did not work, for the life of me I could not see the task in the list. I eventually figured out that in the task.json manifest there was a "visibility" section. The first item was "preview" and this seemed to stop the task from being "shown" somehow. After removing that it worked like a charm.

"visibility": [

Now I can play around with deploying dacpac's wlEmoticon-smile[2]

Wednesday, March 9, 2016

DevConf 2016 A Raging Success

Unless you have been living under a rock in South Africa, you should have been aware that DevConf was held yesterday.

I must admit it was an awesome day with everyone that gathered and all the energy that they brought!

I was lucky enough to be the first speaker in the DevOps track with my session “DevOps Demystified”. I was impressed, having  nearly full room (about 100 people) attending, and hope that everyone gained some value.

My slides can be found here

Kudos to the organisers and looking forward to the next one Smile

Wednesday, February 17, 2016

Application Insights and TypeScript

I’m actively involved in creating extensions on VSTS and one of the questions that comes up a lot is on Telemetry. Are people using the extensions, how are they using it and what about errors and exceptions? It has become such a topic of discussion that Will Smythe has actually gone ahead and given some guidance on how to add Application Insights (AppInsights) telemetry to your extension.

He gives a good overview and example of using AppInsights in a simple JavaScript (and in fact an html page) type application. Personally I prefer using TypeScript to do my JS development.

The method that Will explains and Typescript do not mix as seamlessly as I would like. Luckily there is hope.
Microsoft also provides a TypeScipt type definition for their AppInsights api. Currently it is in preview, but I have not had any problems with it.

You can install it via NPM ilke this:

Install-Package Microsoft.ApplicationInsights.TypeScript -Pre

Once it is installed, it will dump the libraries into the packages folder in the root of the project. There should be two libraries, the JavaScript and the Typescript types.

Under the JavaScript folder (Microsoft.ApplicationInsights.JavaScript.0.21.5-build00175 in this case) you will find the scripts in the content\scripts folder. It has two versions, the full and minified version of the library. In our instance simply copy the minified version (ai.0.21.5-build00175.min.js in this instance) to the scripts folder of your extension.

The package should already have added the typescript definition file to your scripts folder, but in case it has not, under the TypeScript folder (Microsoft.ApplicationInsights.TypeScript.0.21.5-build00175 in this case) you will also find content\scripts folder that contains the type definition (ai.0.21.5-build00175.d.ts in this instance). Copy that to your TypeScript definitions folder.

Now you should be ready to use them. Include the JavaScript library in your extension and reference it in your html page, and add a reference to the TypeScript type definition in your TypeScript files.

/// <reference path="ai.0.21.5-build00175.d.ts" />

To use the library, you need to configure it using a configuration snippet. The configuration snippet contains the instrumentation key that has been setup (following Will’s post):

var snippet: any = {
   config: {
      instrumentationKey: "<<your instrumentation key>>"

You can pass this into the initialisation object :

var init = new Microsoft.ApplicationInsights.Initialization(snippet);

And then from the initialisation object you create an AppInsights instance:

var applicationInsights = init.loadAppInsights();

On the AppInsights instance you can go ahead and start to capture your telemetry using the following:

trackPageView(name?: string, url?: string, properties?: Object, measurements?: Object, duration?: number): void;
trackEvent(name: string, properties?: Object, measurements?: Object): void;
trackAjax(absoluteUrl: string, pathName: string, totalTime: number, success: boolean, resultCode: number): void;
trackException(exception: Error, handledAt?: string, properties?: Object, measurements?: Object): void;
trackMetric(name: string, average: number, sampleCount?: number, min?: number, max?: number, properties?: Object): void;
trackTrace(message: string, properties?: Object): void;

The full code would look something like this:

var snippet: any = {
   config: {
      instrumentationKey: "<<your instrumentation key>>"

var init = new Microsoft.ApplicationInsights.Initialization(snippet);
var applicationInsights = init.loadAppInsights();
applicationInsight.trackMetric("LoadTime", timeMeasurement);

Wednesday, February 10, 2016

Intro to VS Team Services Extensions

Over the last couple of months I have been quite busy with various VSTS extension as part of the ALM Rangers.
You can see some of the extensions that I have developed here and here, and I am currently involved with at least 3 others.

As a quick guidance we decided to do what we call a brownbag session (informal, bring your bagged lunch and listen in type of session) to try and get more of the rangers involved and up to speed.
The session was published on channel 9, so if you are interested in getting up to speed on creating your own extensions, feel free to give it a listen..

Feedback is always welcome.

Thursday, November 12, 2015

JDeveloper and TFS

Oracle developers should be well versed with JDeveloper.
On the SQL side of things, Oracle actually has a plugin available for Visual Studio "Oracle Developer Tools for Visual Studio" giving you a very similar experience to the SQL Server Data Tools.
JDeveloper on the other has is "a freeware IDE supplied by Oracle Corporation. It offers features for development in Java, XML, SQL and PL/SQL, HTML, JavaScript, BPEL and PHP".

This should not stop you from using it with TFS though…
The only thing that intrigues me is the use of workspaces to establish the connection as apposed to creating a connection directly to TFS.

Enable the plugin:

  1. 1) In JDeveloper, go to the extension management page by selecting Help->Check for Updatesclip_image002
  2. Click Next on the sources viewclip_image004
  3. Wait for the extension to load and then type in “Team System” in the search box. This should highlight the Team System extension.
    Select it and click next.clip_image006
  4. Wait for it to download and install, you will probably have to restart JDeveloper.clip_image008
  5. Create a workspace either using Visual Studio or via command line :
  6. Connect to Team System ( Team->Connect to Team System). It may seem that nothing has happened, but go to the next step…clip_image010
  7. Select the workspace created in step 5 (Team -> Team System->Set Workspace and then select the workspace from the list presented):clip_image011
  8. When you open your applications, you should be able to add, check out etc. you files from TFS: by right clicking any files and selecting “Versioning”clip_image012
  9. You can preview the pending changes from Pending Changes (Team-Team System -> Pending Changes) pane.

TFS is no longer "just" a Microsoft / .Net tool… To prove it, have a look at

Monday, November 9, 2015

Multiple TFS_Configuration databases on a single SQL instance

I have been doing a number of upgrades over the last couple of months and have found that doing a migration to a test/dev environment is a good way to gauge the downtime needed to perform an upgrade on the TFS Collection databases.

This works well if you have a spare set of servers / VM's lying around and you are able to do a full migration. I have been in a situation where a new application tier was not much of a problem, but they had an enterprise SQL server setup that we "had to" use.
Even though the "duplicating" of the collection databases is no problem at all, the tfs_configuration database is a different story.

The options are:

  1. Install a temporary SQL server on the application tier and simply use that for the tfs_config database or
  2. Duplicate the tfs_config and then either "point" tfs to the instance in question or select the correct database during (re)configuration

To perform option 2,  simply create a backup of the tfs_configuration database and restore under a different name (on the same server). When you perform an upgrade or (re)configure the TFS application tier you have the option to select the "correct" config database:


If TFS is already configured and you want to change the database after the fact you can follow these steps:

  1. Open up command prompt (run-as admin)
  2. Go to the TFS tools directory (for 2015 the default is C:\Program Files\Microsoft Team Foundation Server 14.0\Tools )
  3. Put TFS to "sleep" : TfsServiceControl.exe quiesce
  4. Backup and restore the config database to the new name
  5. Re-register the database : tfsconfig.exe registerdb /sqlInstance:<<sql-server>> /databaseName:<<new config db name>>
  6. Finally, wake TFS up : TfsServiceControl.exe unquiesce

That should have TFS pointing to the new config database, meaning you can have multiple TFS instances using different configuration database hosted on the same SQL server.

Need help upgrading ? : give us a shout