Blog Stats
  • Posts - 65
  • Articles - 0
  • Comments - 7
  • Trackbacks - 0


Tuesday, December 2, 2014

Wanna use Firefox on the TFS web frontend?

TFS uses a version of NTLM over unsecure HTTP and Firefox doesn't want to allow this by default. Of course, Firefox doesn't tell you it's forbidding something; instead it just acts like you got a 403.

Here's how to fix it so you can use FF on TFS:

  1. In your address bar, go to "about:config"
  2. You should get a little search bar and a giant list of properties. In the search bar, type "ntlm"
  3. Look for the property "network.negotiate-auth.allow-insecure-ntlm-v1" and double-click the "false" in the Value column. It should boldface and turn to "true". The boldface indicates a user-set property.
  4. Restart FF and you're good to go.

Tuesday, September 30, 2014

Microsoft.WITDataStore.dll not found: NuGet NuSpec References

I ported my TFS API code to  use the V12 (2013) assemblies. I then built and created a NuGet package of the TFS API Lib and installed it in an application. Immediately that application build failed because the Microsoft.WITDataStore.dll assmebly was missing from my TFS API NuGet package. 

I found that by default, when the reference tag is not used at all, NuGet adds all files included in the lib folder as references.  I needed the Microsoft.WITDataStore.dll in the package lib folder, but not added as as a reference (this fails).

The solution was to update my NuSpec file to explicitly mark the files I wanted added as references to the project.

<package xmlns="">
      <authors>Bob Hardister</authors>
      <description>A set of methods to get and set information in TFS 2013</description>
      <summary>Library of TFS API Methods.</summary>
        <dependency id="RavenDB.Client" version="2.5.2910" />
        <reference file="Microsoft.TeamFoundation.Build.Activities.dll" />
        <reference file="Microsoft.TeamFoundation.Build.Client.dll" />
        <reference file="Microsoft.TeamFoundation.Build.Common.dll" />
        <reference file="Microsoft.TeamFoundation.Build.Workflow.dll" />
        <reference file="Microsoft.TeamFoundation.Client.dll" />
        <reference file="Microsoft.TeamFoundation.Common.dll" />
        <reference file="Microsoft.TeamFoundation.VersionControl.Client.dll" />
        <reference file="Microsoft.TeamFoundation.VersionControl.Common.dll" />
        <reference file="Microsoft.TeamFoundation.WorkItemTracking.Client.dll" />
        <reference file="Microsoft.TeamFoundation.WorkItemTracking.Common.dll" />
        <reference file="Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll" />
        <reference file="NLog.dll" />
        <reference file="TfsApiLib.Tool.Methods.dll" />
        <reference file="TfsApiLib.Tool.RunProcess.dll" />
      <file src="bin\$configuration$\Microsoft.TeamFoundation.*" target="lib\net45" />
      <file src="bin\$configuration$\Microsoft.WITDataStore.dll" target="lib\net45" />
      <file src="bin\$configuration$\NLog.dll" target="lib\net45\NLog.dll" />
      <file src="bin\$configuration$\TfsApiLib.Tool.*" target="lib\net45" />

Friday, September 12, 2014

TFS Git Delete Remote Branch from Server

You can delete a published branch from Visual Studio, but to remove it from the server use the this git statement from the command prompt of the local repo:

C:\_s\Git\myRepo>git push origin --delete myBranch

Friday, September 5, 2014

Team Explorer Everywhere Command Line Client on a Mac

I was surprised at the dearth of information on this. Here’s the whole enchilada. I did not have to enter user or password information for the TF commands. This could be because my Mac account and password is identical to the Windows AD account and password. Use TF help to get a full listing of commands and TF Help [command] for details on each command.

  1. Download TEE-CLC on your Mac and unzip/move the TEE-CLC-x.x.x folder under your Applications folder.
  2. Open the Terminal command line on you Mac (search for Terminal)
  3. To see the current execution path on your Mac:
    • echo $PATH
  4. Enter the following to add the TEE-CLC to you path:
    • export PATH=$PATH:/Applications/{TEE CLC folder name}
    • example: export PATH=$PATH:/Applications/TEE-CLC-11.0.0
  5. Enter the echo command again to verify the TEE CLC folder has been added to the path
  6. Install the Java JDK (installing just the run time is  not sufficient)
  7. You should be able to execute the TF command from the Terminal window once the Java JDK install has completed
  8. Create a folder to store your TFS source control files. I used \Documents\_s\MyCollection
  9. Accept the TCC license by executing:
    • tf eula
  10. Create the workspace:
    • tf workspace -new -collection:{url} -location:server {workspace name}
  11. Create the workspace mapping
    • tf  workfold -map -collection:{url} -workspace:{workspace name} '$/' '/Users/bob_hardister/Documents/_s/MyCollection'
  12. Navigate to your local workspace folder in the Terminal window to run TF Get and other workspace centric commands
  13. A Get command would then be
    • tf get -r  '$/…desried TFS server location to pull from'

Friday, July 25, 2014

Move TFS 2013 Git Repo to a Different Team Project

1. Go to the target team project admin site

2. Create the new repo on the TFS server (with the same name as the source repo except under the target team project)

3. Go to the target team project site and display the empty repo. Note the new repo remote url

4. Open Visual Studio 2013 team explorer connect tab (Update 2 or >) and connect to the remote source repo

5. Clone the repo under the new team project or other location

6. Right click on the new (cloned) local repo and click Open Command Prompt

7. Copy the new remote url of the target team project repo (see #3 above)

8. Execute the following command in the command prompt:

[new local repo location]>git remote set-url origin [new remote url]

9. Right click on the new local repo in the Visual Studio 2013 team explorer connect tab

10. Click Open

11. Click "Unsynced Commits"

12. Click the "Sync" button to push the local repo to the remote

13. Go to the remote repo site and refresh to display the code just pushed from the local repo

Tuesday, July 8, 2014

TFS 2013 Build Process Template – Change the “AutomatedTest” Argument Default Value

It should be simple, but due to the length of the string, the syntax was not obvious. The out-of-the-box default is as follows. Note the backslash escape character and stick to the syntax:

{New Microsoft.TeamFoundation.Build.Common.BuildParameter(" { ""AssemblyFileSpec"": ""**\\*test*.dll;**\\*test*.appx"", ""RunSettingsFileName"": null, ""TestCaseFilter"": """", ""RunSettingsForTestRun"": { ""ServerRunSettingsFile"": """", ""TypeRunSettings"": ""Default"", ""HasRunSettingsFile"": false }, ""HasRunSettingsFile"": false, ""HasTestCaseFilter"": false, ""ExecutionPlatform"": ""X86"", ""FailBuildOnFailure"": false, ""RunName"": """" } ")}

If you remove the values to expose the syntax you get:

{New Microsoft.TeamFoundation.Build.Common.BuildParameter("")}

To add another “test” to the template use this:

{New Microsoft.TeamFoundation.Build.Common.BuildParameter(""), 
New Microsoft.TeamFoundation.Build.Common.BuildParameter("")}

and just provide the desired values. Here’s what I ended up with:

{New Microsoft.TeamFoundation.Build.Common.BuildParameter(" { ""AssemblyFileSpec"": ""*UnitTests\\*Tests.dll"", ""RunSettingsFileName"": null, ""TestCaseFilter"": """", ""RunSettingsForTestRun"": { ""ServerRunSettingsFile"": """", ""TypeRunSettings"": ""Default"", ""HasRunSettingsFile"": false }, ""HasRunSettingsFile"": false, ""HasTestCaseFilter"": false, ""ExecutionPlatform"": ""X64"", ""FailBuildOnFailure"": false, ""RunName"": ""Unit"" } "), New Microsoft.TeamFoundation.Build.Common.BuildParameter(" { ""AssemblyFileSpec"": ""*IntegrationTests\\*Tests.dll"", ""RunSettingsFileName"": null, ""TestCaseFilter"": """", ""RunSettingsForTestRun"": { ""ServerRunSettingsFile"": """", ""TypeRunSettings"": ""Default"", ""HasRunSettingsFile"": false }, ""HasRunSettingsFile"": false, ""HasTestCaseFilter"": false, ""ExecutionPlatform"": ""X64"", ""FailBuildOnFailure"": false, ""RunName"": ""Integration"" } ")}

Nuget Push to Klondike Requires Packages Appended to Source and SetApiKey URL

When we upgraded to NuGet 2.8 our PUSH command  starting failing.  The first fix was to appended “packages” to the source URL string like this:

We use the SetApiKey command on our server so we don’t have to explicitly include the API key itself in the push command. After making the change above we had issues with the PUSH command not finding the API key. To fix this, we appended “packages” to the source argument of the SetApiKey command like this:

nuget setApiKey myApiKey -Source

Everything then worked fine as before.

Wednesday, June 25, 2014

Get the Last Build By Build Number with Visual Studio ALM Team Foundation Server API

Here is a handy TFS 2013 build activity for getting the last build by build number filter. In this case:

  • We get the 4th version node number: we call it the revision number
  • We use semantic versioning and some of our branches are “version named” i.e. 1.4.10
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Workflow;

namespace Alm.BuildActivities
    public sealed class GetVersionNamedBranchLastRevisionNumber : CodeActivity
        #region arguments
        public InArgument<string> BuildDefinitionName { get; set; }
        public InArgument<string> CollectionUrl { get; set; }
        public InArgument<string> ProjectName { get; set; }
        public InArgument<string> VersionNamedBranch { get; set; }
        public OutArgument<int> CurrentRevisionNumber { get; set; }

        protected override void Execute(CodeActivityContext context)
            #region initialize fields
            context.SetValue(this.CurrentRevisionNumber, 0);
            string buildDefinitionName = context.GetValue(this.BuildDefinitionName);
            string collectionUrl = context.GetValue(this.CollectionUrl);
            string projectName = context.GetValue(this.ProjectName);
            string versionNamedBranch = context.GetValue(this.VersionNamedBranch);
            int currentRevisionNumber = 0;

                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(collectionUrl));

                if (!(tpc == null))
                    var bs = tpc.GetService<IBuildServer>();
                    var buildDefSpec = bs.CreateBuildDefinitionSpec(projectName, buildDefinitionName);
                    buildDefSpec.Options = QueryOptions.None;
                    var buildDef = bs.QueryBuildDefinitions(buildDefSpec).Definitions.FirstOrDefault();

                    var buildSpec = bs.CreateBuildDetailSpec(buildDef);
                    //gets only "stable builds" of the version named branch
                    buildSpec.BuildNumber = string.Format("*_{0}.?", versionNamedBranch); 
                    buildSpec.QueryDeletedOption = QueryDeletedOption.IncludeDeleted;
                    buildSpec.MaxBuildsPerDefinition = 1;
                    //gets last stable build of the version named branch
                    buildSpec.QueryOrder = BuildQueryOrder.StartTimeDescending; 

                    var buildQuery = bs.QueryBuilds(buildSpec).Builds.FirstOrDefault();

                    if (buildQuery == null)
                        currentRevisionNumber = 0; //there aren no stable builds of this version named branch
                        context.SetValue(this.CurrentRevisionNumber, currentRevisionNumber);
                        var lastStableBuildNumber = buildQuery.BuildNumber;
                        string currentRevisionNumberString = lastStableBuildNumber
                            .Substring(lastStableBuildNumber.LastIndexOf(".") + 1);
                        bool result = Int32.TryParse(currentRevisionNumberString, out currentRevisionNumber);
                        if (result)
                            context.SetValue(this.CurrentRevisionNumber, currentRevisionNumber); 
                            string text = "ERROR: unable to parse to int the currentRevisionNumberString value:";
                            throw new Exception(string.Format("{0} {1}.", text, currentRevisionNumberString));
                    throw new Exception("ERROR: unable to connect to TFS collection");
            catch (Exception ex)
                throw new Exception(string.Format("ERROR. Exception message: {0}", ex.Message));

Monday, April 28, 2014

Delete Build Drop Locations Some Number of Days Old

We don’t need to keep our drop folders after a week. Here some code to accomplish that.

public void SetDeleteBuildDropFolder()
    //method parms
    string collectionUrl = "http://myCollectionUrl";
    string projectName = "myTeamProjectName";
    var buildDefinitionNames = new List<string>();
    var fromDate = DateTime.Now.AddDays(-8);
    //execute method
    var buildsDropFoldersDeleted = tfsApi.SetDeleteBuildDropFolder(collectionUrl, projectName, buildDefinitionNames, fromDate);

    //evaluate result
public Dictionary<string, string> SetDeleteBuildDropFolder(string collectionUrl, string projectName, 
List<string> buildDefinitionNames, DateTime fromDateTime) { var buildsDropFoldersDeleted = new Dictionary<string, string>(); try { TfsTeamProjectCollection tpc = GetCollection(collectionUrl); if (!(tpc == null)) { var bs = tpc.GetService<IBuildServer>(); foreach (var buildDefName in buildDefinitionNames) { var buildSpec = bs.CreateBuildDetailSpec(projectName, buildDefName); buildSpec.QueryOptions = QueryOptions.None; buildSpec.InformationTypes = null; buildSpec.MaxBuildsPerDefinition = 100; buildSpec.QueryOrder = BuildQueryOrder.StartTimeDescending; buildSpec.QueryDeletedOption = QueryDeletedOption.ExcludeDeleted; if (buildSpec != null) { var buildsDrops = bs.QueryBuilds(buildSpec).Builds.Where(x => x.FinishTime < fromDate)
.Select(y => new { y.Uri, y.DropLocation }); foreach (var build in buildsDrops) { if (Directory.Exists(build.DropLocation)) { try { var bSpec = bs.CreateBuildDetailSpec(projectName, buildDefName); bSpec.QueryOptions = QueryOptions.None; bSpec.InformationTypes = null; bSpec.QueryDeletedOption = QueryDeletedOption.ExcludeDeleted; //Using the build service you can delete multiple build drop folders at the same time //var targetBuild = bs.QueryBuilds(bSpec).Builds.Where(b => b.Uri == build.Uri).ToArray(); //bs.DeleteBuilds(targetBuild, DeleteOptions.DropLocation); //Here I'm only deleting a single build drop folder at a time var targetBuild = bs.QueryBuilds(bSpec).Builds.Where(b => b.Uri == build.Uri).FirstOrDefault(); if (targetBuild.KeepForever) { targetBuild.KeepForever = false; targetBuild.Save(); } targetBuild.Delete(DeleteOptions.DropLocation); buildsDropFoldersDeleted.Add(targetBuild.BuildNumber, build.DropLocation); } catch (Microsoft.TeamFoundation.Build.Client.BuildDefinitionNotFoundException) { //build not found } } } } else { return null; } } return buildsDropFoldersDeleted; } else { return null; } } catch (Exception ex) { return null; } }

Monday, January 20, 2014

Formatting Command Output on the TFS Build Report

The Team Foundation Server build can include command output in the report log or summary by using the stdOutput and errOutput variables in the WriteBuildMessage or WriteCustomSummaryInformation activities. I’ve often been frustrated with bad formatting that you get.  However, I found that if you simply use String.Format with stdOutput or errOuput, you get much better formatting. For example, with String.Format("{0}", stdOutput) you get correct line returns.



Copyright © Bob Hardister