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

 

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="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
    <metadata>
      <id>ALM.Tools.TfsApiLib</id>
      <version>0.0.0.0</version>
      <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>
      <dependencies>
        <dependency id="RavenDB.Client" version="2.5.2910" />
      </dependencies>
      <references>
        <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" />
      </references>
    </metadata>
    <files>
      <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" />
    </files>
</package>

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:

myFeed.com:8080/api/packages

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 myFeed.com:8080/api/packages

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
{
[BuildActivity(HostEnvironmentOption.Agent)]
    public sealed class GetVersionNamedBranchLastRevisionNumber : CodeActivity
    {
        #region arguments
        [RequiredArgument]
        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; }
        #endregion

        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;
            #endregion

            try
            {
                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(collectionUrl));
                tpc.EnsureAuthenticated();

                if (!(tpc == null))
                {
                    var bs = tpc.GetService<IBuildServer>();
                    var buildDefSpec = bs.CreateBuildDefinitionSpec(projectName, buildDefinitionName);
                    buildDefSpec.PropertyNameFilters.Add("Name");
                    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);
                    }
                    else
                    {
                        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); 
                        }
                        else
                        {
                            string text = "ERROR: unable to parse to int the currentRevisionNumberString value:";
                            throw new Exception(string.Format("{0} {1}.", text, currentRevisionNumberString));
                        }
                    }
                }
                else
                {
                    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.

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

    //evaluate result
    Assert.IsNotNull(buildsDropFoldersDeleted);
}
        
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.

Tuesday, January 14, 2014

Making Agile Work on Large, Complex Projects


Our TFS Austin User Group hosted this presentation last month given by Mike Haze, Director of Product Management for Volusion.  It was one of the best meetings we’ve had.  Here’s the abstract and a link to the recording of the meeting.

Recording Link: http://usergroup.tv/videos/making-agile-work-on-large-complex-projects 

Presentation: Making Agile Work on Large, Complex Projects

There is a widely accepted myth that extremely complex software platforms, committed delivery schedules, large development teams, and dynamic business environments are in direct opposition to agile development processes and tools and if your product / project fall into one of these categories you will struggle with fully embracing agile methodologies. This is simply not the case, you can fully adopt and leverage an agile methodology through out the full product lifecycle, gaining all the advantages and leverage the tools your teams are already using today and are tightly integrated into the development process. We will explore how Volusion is currently leveraging TFS throughout the complete product lifecycle and discuss some of the key challenges and successes that we've experienced along the way.

Speaker

Mike Haze is the Director of Product Management at Volusion. Mike holds a number of patents including "System and method for migration of digital assets" and "System and method for self-provisioning of virtual images." Beginning his career as a Software Developer, Mike has served as a Product Experience Strategist for Dell and the Director of Product Development and Innovation for Dun and Bradstreet.

Volusion is a leading e-commerce software development company based in Austin with $12B in merchant sales worldwide, over 40,000 online stores and over 450 employees. Volusion has won the Austin Business Journal's award for Best Places to Work for 2012 and 2013.

TfsUGMikeHaze1 TfsUGMikeHaze2

 

 

Copyright © Bob Hardister