Taking the SuggestedValues rule one step further

Have you ever created a custom field on a TFS work item, that you wanted to be free form entry but save the entries so the next person can select from the previous entries.

You could write a custom control to do this also. However having a service in the back ground to manage this at the server is much easier. And does not have to be installed on each client. You first need to create a Web Service that will subscribe to TFS’s Bissubscribe.exe. There is plenty of information out there to show you the mechanics of this. Check out Ewald Hofman’s blog for the details on creating a web service to subscribe to TFS. It’s an old post but still useful, easy to understand and follow.

As an example, let’s assume the field we want to do this for on is called Requested By. Where users can select from the Developers or Business User Security groups or enter a name that is not a member of a group in TFS at all. To solve this problem we created a GlobalList called RequestedBy. Then we added a SuggestedValues rule to the field that included the Developers and Business Users groups, as well as the RequestedBy GlobalList.

The field definition looks like this.

<FIELD name="Requested By" refname="RequestedBy" type="String">
    <SUGGESTEDVALUES>
        <LISTITEM value="[Project]\Developers" />
        <LISTITEM value="[Project]\Business Users" />
        <GLOBALLIST name="RequestedBy" />
    </SUGGESTEDVALUES>
    <REQUIRED />
</FIELD>

 

If the user enters a value into the field that is not from one of the TFS groups or the globalist the web service kicks in and adds the value to the globalist. So the next user that enters that name will find them in the list and is less likely to spell the name differently than the first person.

And here is the code in the web service that accomplishes that task.

public void AddToGlobalList(WorkItemStore workItemStore, string globalList, string value)
{
    if (!string.IsNullOrWhiteSpace(value))
    {
        var globalLists = workItemStore.ExportGlobalLists();
        var node = globalLists.SelectSingleNode(
    string.Format("//GLOBALLIST[@name='{0}']/LISTITEM[@value='{1}']", globalList, value));

        if (node == null)
        {
            node = globalLists.SelectSingleNode(
        string.Format("//GLOBALLIST[@name='{0}']", globalList));
                    
            if (node != null)
            {
                var valueAttr = globalLists.CreateAttribute("value");
                valueAttr.Value = value;
                var child = globalLists.CreateElement("LISTITEM");
                child.Attributes.Append(valueAttr);
                node.AppendChild(child);
                workItemStore.ImportGlobalLists(globalLists.DocumentElement);
            }
        }
    }
}

Creating a linked Workitem via the TFS API

I have a customer that wanted to create Approvals for a particular work item type. We decided the best way to do this would be to create an Approval work item type and a new Link type called Approvals.

I found it difficult to find an example out there of creating new work item and linking it to another using my own link type. Once I got it working I thought I would Blog it so the next person looking for this has one more example.

Here are the steps; first using the process editor I created a new Link Type (see screen shot below for details). You can use the command line tool witadmin importlinktype to import your link type to the project.

image

Now to write a web service that is called via bissubscribe to create approvals for my source work item when the source work item is created. In the real code this was a bit more complicated. We had to look up who many approvals were required and create on approval for each person that was required. I have trimmed the code down to the bare necessities just to illustrate how to create the link.  

Therefore here is a sample of the code to create a new work item of the type Approval and link it to the source work item with the relationship Approved By.

//Get the TFS Collection and ensure Authenticated
TfsTeamProjectCollection TfsCollection = new TfsTeamProjectCollection(new Uri "https://Server/tfs/Collection"));
TfsCollection.EnsureAuthenticated();
//Get the Work item store
WorkItemStore workItemStore = TfsCollection.GetService<WorkItemStore>();
//Get the project 
Project project = workItemStore.Projects["MyProject"];
 
//Get the Source Work item (Take for granted I have been passed the ID of the work item to be approved
WorkItem source = workItemStore.GetWorkItem(ID);
//Make a copy of that as an Approval. This way all the common data is pushed into the approval
WorkItem approval = source.Copy(project.WorkItemTypes["Approval"], WorkItemCopyFlags.None);
//Remove the related link that is created by the copy method
approval.Links.Clear();
//Save the new work item
approval.Save();

//Create a link of the type Approvals
WorkItemLinkType linkType = workItemStore.WorkItemLinkTypes["Approvals"];
//Create a linktypeend using the foward name in out case that is Approved By
WorkItemLinkTypeEnd linkTypeEnd = workItemStore.WorkItemLinkTypes.LinkTypeEnds[linkType.ForwardEnd.Name];
//Add the link to the source work item
source.Links.Add(new RelatedLink(linkTypeEnd, approval.Id));
//Save
source.Save();

New TFS Administration Tool

One of the tools any TFS admin keeps in their toolbox is the TFS Administration Tool. This tool makes it very easy to manage security for TFS. Allowing you to manage user permissions on all three platforms used by TFS. Specifically TFS, SharePoint and Reporting Services.

Download version 2.2 here.

Toronto ALM User Group

Happy New Year everyone.

We have two great sessions to start 2013.

Patterns of Testable Software – with Asaf Stone on January 24th

2013 ALM Summit in Review – with Jeremy Garner-Howe on February 7th

Looking forward to seeing you there.

Mapping to a TFS Source Control Folder

So often I see developers mapping to their local folder from the middle of the source control tree to a folder on their desktop, then another folder to a different location. It gets very messy very quickly.

Some people may like to map folders this way, however I prefer a cleaner mapping implementation. When working on a team I would rather have the same folder structure as the server and everyone else on the team. Also it’s nice not to have to map each app I work on. I would rather just map once and be done with it.

Here is what I do: From a clean never been mapped TFS source control repository. If you already have  mappings check everything in and remove them before doing this. (These instructions are for Team Explorer 2012)

Open the Source Control Explorer

Select the top node which should be your Server\Collection

Right click and select Advanced | Map to Local Folder from the context menu

Create a folder on the drive of your choice with the same name as the Collection. I like to create a Source folder then inside that folder create the Folder with the same name as the collection.  That way if I have more than one Collection they are separate folders but all under Source.

image

 

 

 

 

 

Once you hit the MGetLatestap button you will be prompted to get latest of everything in the collection.

 

 

 

 

I recommend you select No. I doubt you want everything, do you?

Now traverse the Source Control tree look and watch the Local Path at the top it changes as you move. To get a particular application just right click on the folder and select Get Latest Version and it will get it into the folder structure you see.

Have everyone on the team do this. Then when you go from machine to machine you always know where to find the source. Also it looks just like the server.

Cloaked folders in the TFS Build Workspace

 

Here is a little Trick I find most people don’t know about.

When setting up a Build Definition you have to tell the build server where to get the source code from. We do this by declaring the folders to download from on the workspace tab of the build definition. It takes time to download all the files to the build server so you don’t want to get any unnecessary folders from source control.

Generally you can just select the root of the branch and pick up everything from there. Although there are times when the build you are creating does not require all the files in the branch. Lets say for example that you have two builds that run one that only builds the application and one for your WIX projects to create an install package. You likely want to keep all the files together for branching purposes. Something like this:

image

The folders in my example are for the following:
Builds files used by the build process specific to this application. Includes third party DLL’s we do not have the source code for.
Install WIX Project.
Resources Various resource files used by the application.
Source Application Source Code.

Now what I want is to get certain folders when building the app for a CI build and different ones when creating an install package.

CI Build

Install Package

Builds

Builds

Includes

Includes

Resources

Install

Source

 

I could just do this. But then I am getting more than I need in both cases.

image

 

 

 

Or to get just what I need I could do this. (Making sure I put everything into the correct folder on the build agent.

CI Build: image

 

 

 

 

Installation Package Build:image

 

 

 

 

Or I could use the cloaked status to let the build know not to get a particular folder.

Therefore on the CI Build where I want everything but the Install Folder I could do this: image

 

 

 

And on the Install Package Build I don’t need Source or Resources so I could do this:image

Concatinating string in a batch file

Batch file? Yes you heard me, batch file, you know .cmd.

This is an odd post for me, however I needed to do this recently and don’t want to forget how I did it. Smile

 

When automating builds I often take advantage of invoke process. It’s a nice way to keep my build process generic and call out to a process that may change over time or is specific to branch I am building. It allows me to keep some of the process specific to the source code, by storing the batch file with the source code. This also allows me to version the batch file if it changes over time, and ensure it available to the build server without installing it on the build server.  None of this has anything to do with my blog post. Whatever the reason you may be calling out to a batch file using invoke process read on.

Have you ever had trouble passing variables like DropLocation or SourcesDirectory. If they have spaces in them you will need to put them in quotes. Lets say I want to pass the DropLocation to a batch file.

The arguments property of my invoke process would look like this. """" + DropLocation + """"

Notice the double quotes around the variable, to ensure they are passed to the batch file as one argument.

“\\My File Server\Drops\BuildDefinition_1.3.4636.1”

Without the quotes in this example my batch file would have received 3 arguments

  1. \\My
  2. File
  3. Server\Drops\BuildDefinition_1.3.4636.1

Therefore I need the Quotes.

In my batch file I want to access files in a subfolder of my DropLocation. So I need to concatenate the path passed in with another folder. Ultimately I want the location

\\My File Server\Drops\BuildDefinition_1.3.4636.1\MyFolder

The problem is with the double quote at the end of the argument this %1\MyFolder would end up being this “\\My File Server\Drops\BuildDefinition_1.3.4636.1”\MyFolder

Here is how to fix that problem.

First create a variable to hold your argument

set DROPLOCATION=%1

Then when you go to use the variable use a little string manipulation. Specifically ( :~f,e ) where f = the number of characters to strip from the start of the argument and e the number of characters to strip from the end.

Therefore to get ride of the double quotes at the end of our argument just remove the last character.

Like this %DROPLOCATION:~0,-1%\MyFolder"

The above syntax will result in this “\\Server\Drops\BuildDefinition_1.3.4636.1\MyFolder” making it possible to add my folder in the batch file instead of in the build process.

Serious Test Case Design

 

I am doing part of a talk at the Microsoft Canada Office on Thursday September 13th at 6:00pm.

Here is the blurb:

Testing with Microsoft Test Manager

Coded UI tests provide a way to create fully automated tests to validate the functionality and behaviour of your application’s user interface. We’ll cover some of the ways you can use these methods of testing with TFS 2012 to increase your teams productivity. Accelerate your testing with Fast Forward for Manual Testing to quickly re-run test steps or even entire test cases in the future.

Come out it should be fun.

TFS 2012 Team Explorer

I did a little video for Tech Days TV demoing some of the new features of the Team Explorer.

You can check it out here.

What’s new in TFS?

Recently I have been on Tech Days TV and Align IT with some friends of mine.

All the shows, pertain to the next version of TFS coming out in 2012.

If you want to watch them here is the link.