Archive

Posts Tagged ‘TFS2010’

TFS2012: How to delete a workspace using the tf command


Today while I am writing another blog post, I encountered the following error

Exception Message: The working folder C:\Builds\5\MyTeamProject\UnitTestProject1\src is already in use by the workspace 6_5_TFS2012Build1;TFS2012BUILD1$ on computer TFS2012BUILD1. The Build Agent TFS2012Build1 – Agent1 is running as a different user Administrator and local paths can only be mapped to a single workspace. To resolve this issue, you can configure the Build Service to run as the user who owns the conflicting workspace, or you can delete the workspace using the ‘tf workspace’ command. (type WorkingFolderInUseException)

I received that error because, I changed the run as service account for the Build Controller. From a machine that has Visual Studio installed, open the VS command prompt.

Then, the first thing you want to do is check what switches TF workspace has by running the following command


tf workspace /?

To learn more about the switches or arguments, check this msdn article http://msdn.microsoft.com/en-us/library/y901w7se(v=vs.100).aspx

You can also use the tf workspaces to target multiple workspaces or to list all workspaces for a collection


tf workspaces /collection:http://tfs2012express:8080/tfs/defaultcollection Collection:http://tfs2012express:8080/tfs/defaultcollection

The above will return you the workspaces on the current machine. If you want to view all workspaces, you need to use the /computer switch


tf workspaces /collection:http://tfs2012express:8080/tfs/defaultcollection Collection:http://tfs2012express:8080/tfs/defaultcollection /computer:*

image

In my case, I am using the following switches


tf workspace /delete /collection:<a href="http://tfs2012express:8080/tfs/defaultcollection 6_5_tfs2012build1;tfs2012build1$

image

Type Yes and press enter

Advertisements

Customize Build Template in TFS2012 to Build All Solutions-Part 2


This post improves the Users Experience for Customize Build Template in TFS2012 to Build All Solutions-Part 1 solution. In this article, I will create a custom editor (dialog box) that will show all solutions in the source control repository and comma separate the selected values into the value cell of the Solutions argument we created in the previous post. The editor also reads the value in the PropertyGrid and select the matching solutions in the dialog.

History and Credits

I built this solution to generate MSI’s for Biztalk projects with the deployment framework after building the solution back in 2011 or early 2012. But to simplify the example, I am using this approach to build the selected solutions in the version control. I remember at the time I learned how to build a UIEditor for the build definition from http://blogs.msdn.com/b/jpricket/archive/2010/01/18/tfs-2010-custom-process-parameters-part-3-custom-editors.aspx

Create the Solutions’ Selector Dialog

My approach to create the dialog starts by creating the following files

C# Library Project: I am calling it TFSBuildEditors

SelectableItemsUIEditor.cs: this is the editor class that need to be referenced with the argument. It is also responsible for launching the dialog. Class extends UITypeEditor.

SelectableItemsForm: this is a WindowsForm Item. To launch the dialog (form) we need a reference to IWindowsFormsEditorService. That service supports only Windows Form instances.

SelectableItemsControl.xaml: I am using a WPF control here which is embedded into the WindowForm window. I am using an Element Host control to do so. I am using WPF control here because it makes my life easier by using binding 🙂

SelectableItem.cs: is a class the contains two properties: Item and IsItemChecked.

TfsHelper.cs: Contains some of the code we used in the previous post to retrieve the solutions from source control.

image

Creating the Project

Create a C# library project targeting .NET 4.5 (I am using Visual Studio 2012)

Add the following references:

Microsoft.TeamFoundation.Build.Client.dll

Microsoft.TeamFoundation.Client.dll

Microsoft.TeamFoundation.VersionControl.Client.dll

Creating TfsHelper

Add a folder, I am calling it TFSAPI

Added a c# class and call it TfsHelper.cs

Add the following code:


using System.Collections.Generic;
 using System.Linq;
 using Microsoft.TeamFoundation.VersionControl.Client;

namespace TFSBuildEditor.TFSApi
 {
 public class TfsHelper
 {
 public static IEnumerable<string> GetPathList(string pattern,
 VersionControlServer versionControlServer)
 {
 List<string> solutionList = new List<string>();
 var lists = versionControlServer.GetItems(pattern,
 VersionSpec.Latest,
 RecursionType.Full,
 DeletedState.NonDeleted,
 ItemType.File);

if ( lists.Items.Any())
 {
 var list = lists.Items
 .Select(i => i.ServerItem)
 .ToList();
 return list;
 }

return solutionList; ;
 }
 }
 }

SelectableItem

Create a C# class and call it SelectableItem

Use the following code to define it


using System;
 using System.ComponentModel;

namespace TFSBuildEditor
 {
 public class SelectableItem : INotifyPropertyChanged
 {
 private string item;
 public string Item
 {
 get { return item; }
 set
 {
 if (value != item)
 {
 item = value;
 OnPropertyChange("Item");
 }
 }
 }

private Boolean isItemChecked;
 public Boolean IsItemChecked
 {
 get { return isItemChecked; }
 set
 {
 if (value != isItemChecked)
 {
 isItemChecked = value;
 OnPropertyChange("IsPathChecked");
 }
 }
 }

public event PropertyChangedEventHandler PropertyChanged;

public void OnPropertyChange(string propertyName)
 {
 if (PropertyChanged != null)
 {
 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
 }

}
 }
 }

SelectableItemControl.xaml

Add a WPF User Control to the project

I am using the following code for the xaml


<UserControl x:Class="TFSBuildEditor.SelectableItemsControl"
 xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;">http://schemas.microsoft.com/winfx/2006/xaml/presentation"</a>
 xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml&quot;">http://schemas.microsoft.com/winfx/2006/xaml"</a>
 xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;">http://schemas.openxmlformats.org/markup-compatibility/2006"</a>
 xmlns:d="<a href="http://schemas.microsoft.com/expression/blend/2008&quot;">http://schemas.microsoft.com/expression/blend/2008"</a>
 mc:Ignorable="d"
 d:DesignHeight="300" d:DesignWidth="300">
 <Grid>
 <Grid.RowDefinitions>

</Grid.RowDefinitions>
 <ListBox Margin="0,0,0,0" Name="SelectableItemsList" ItemsSource="{Binding ItemsCollection}">
 <ListBox.ItemTemplate>
 <DataTemplate>
 <StackPanel Margin="0,0,0,17" Orientation="Horizontal">
 <CheckBox IsChecked="{Binding IsItemChecked, Mode=TwoWay}"/>
 <TextBlock Text="{Binding Item, Mode=TwoWay}" TextWrapping="Wrap"/>
 </StackPanel>
 </DataTemplate>
 </ListBox.ItemTemplate>

</ListBox>

</Grid>
 </UserControl>

SelectableItemsForm

Add a WindowsForm to the project

Add an ElementHost, OK button and a Cancel button. Adjust the anchor property for each of the controls

image

Right click on the form in the solution explorer and click view code

1-30-2013 1-52-44 AM

I am using the following code, I added comments to make easier to understand what I am doing


using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Windows.Forms;
 using System.Collections.ObjectModel;
 using Microsoft.TeamFoundation.VersionControl.Client;
 using TFSBuildEditor.TFSApi;

namespace TFSBuildEditor
 {
 public partial class SelectableItemsForm : Form
 {
 public SelectableItemsForm()
 {
 InitializeComponent();

}

//Property will hold the comma separated values
 public string SelectedItems { get; set; }

//VersionControlServer instance
 public VersionControlServer VersionControlServer { get; set; }

//Collection is bound to the WPF control
 private ObservableCollection<SelectableItem> itemsCollection = null;
 public ObservableCollection<SelectableItem> ItemsCollection
 {
 get
 {
 if (itemsCollection == null)
 {
 itemsCollection = new ObservableCollection<SelectableItem>();
 }
 return itemsCollection;
 }
 set
 {
 itemsCollection = value;
 }
 }

public void Initialize()
 {
 InitializeWPFControl();
 //Idealy you want to read the workspace map
 var projList = TfsHelper.GetPathList("$/*.sln", VersionControlServer);

List<string> selectedProjects = new List<string>();

//Is the value in the propery grid null or whitespace
 if (!string.IsNullOrWhiteSpace(SelectedItems))
 {
 //convert comma seperated string to List<string>
 selectedProjects = SelectedItems.Replace(@"\", @"/").Split(char.Parse(",")).ToList();
 }

//Value cell had valid entries
 if (selectedProjects.Any())
 {
 //for each solution in version control
 foreach (var item in projList)
 {
 //Build the ItemsCollection (list of solutions) and set IsItemCheck to true if
 //The solution was checked before or typed properly in the value cell
 ItemsCollection.Add(
 new SelectableItem
 {
 IsItemChecked = (selectedProjects.Contains(item) ? true : false),
 Item = item
 }
 );
 }
 }
 else
 {
 foreach (var item in projList)
 {
 ItemsCollection.Add(new SelectableItem { IsItemChecked = false, Item = item });
 }
 }

}

private void InitializeWPFControl()
 {
 //Create new instance of the wpf control
 var selectableItemsControl = new SelectableItemsControl();
 //bind the windows form to teh WPF control
 selectableItemsControl.DataContext = this;
 //Assign the wpf control to the element host
 this.elementHost1.Child = selectableItemsControl;
 }

private void Cancel_Click(object sender, EventArgs e)
 {
 this.Close();
 }

private void OkButtons_Click(object sender, EventArgs e)
 {
 //Selected solutions?
 if (ItemsCollection.Any())
 {
 //comma seperate selected solutions
 SelectedItems = string.Join(",", ItemsCollection.Where(p => p.IsItemChecked)
 .Select(p => p.Item)
 .ToArray()).Replace(@"/", @"\");

}
 else
 {
 //Set SelectedItems to empty string
 SelectedItems = string.Empty;
 }
 DialogResult = System.Windows.Forms.DialogResult.OK;
 this.Visible = false;
 }

}
 }

SelectableItemsUIEditor

This Edit will be used later on in the meta data of the WorkFlow build Template. It is the entry point to launch the dialog. I am using the following code


using System;
 using System.Drawing.Design;
 using System.ComponentModel;
 using System.Windows.Forms.Design;
 using System.Windows.Forms;
 using Microsoft.TeamFoundation.VersionControl.Client;

namespace TFSBuildEditor
 {
 public class SelectableItemsUIEditor:UITypeEditor
 {
 public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
 {
 if (provider != null)
 {
 IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

if (editorService == null)
 {
 return value;
 }

//create new instance of the windows form
 using (SelectableItemsForm dialog = new SelectableItemsForm())
 {
 //set the VersionControlServer property
 dialog.VersionControlServer = (VersionControlServer)provider.GetService(typeof(VersionControlServer));

//Set the SelectedItems string property to the value from the property grid
 dialog.SelectedItems = value as string;

//Call initialize method that calls the tfs api and build the wpf control and populate it with data
 dialog.Initialize();

//Show dialog
 if (editorService.ShowDialog(dialog) == DialogResult.OK)
 {
 value = dialog.SelectedItems;
 }
 }
 }

return value;
 }

public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
 {
 return UITypeEditorEditStyle.Modal;
 }

}
 }

Deploy the editor

Build the project

Copy the dll and the pdb file to C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PrivateAssemblies

Modify build template

Open the build definition template from Source Control\BuildProcessTemplate

image

Click on the small button next to the default value for the Metadata argument

The parameter name must match the name of the argument

Fill the Editor’s textbox with the fully qualified name for the editor

image

Click OK and Check in the Build Process Template

Testing

Close and open Visual Studio

Open your build definition

image

To debug, open another instance of Visual Studio and attached it other instance that has the build definition open

Click on Tools—>Attach to Process

image

Select devenv.exe and click attach. Make sure your code has a break point in the EditValue method in SelectableItemsUIEditor and then click on the ellipsis button in the build definition

image

image

Team Explorer: Save Codeplex Username and Password


A friend of mine emailed me few minutes ago saying that it is too annoying that TFS keeps asking him to enter his username and password and asked me if there is a way to save the username and password. The following are the steps to do so:

 

Using Windows 7:

Open Windows Explorer and go to Control Panel\User Accounts and Family Safety\Credential Manager

Click Add a Windows Credential

image

 

Enter tfs.codeplex.com in the “Internet or network address” textbox

Enter your username and password. To find out your username check this Post

image

TFS2010 Add New Argument/Parameter to a Build Template


This post was created in response to this forum question on msdn:

http://social.msdn.microsoft.com/Forums/en-US/tfsbuild/thread/91619304-93df-4635-ba89-7c16f477b852

It is fairly simple to add a new argument to your build template

Click on the Arguments tab

Scroll all the way down and click “Create Argument”

Type the name of your argument (e.g. BuildEnvironment)

To make the argument required, to customize its category, or use a customized editor, we need to create a new parameter in Metadata property as shown in the following image

In the team definition, I added Switch activity (can be added where you want to use that argument) and changed the expression to BuildEnvironment.ToLower to make it case insensitive. Switch activity can be replaced with If activity if the argument can be set to only two values

Click on “Add new case”, type case value to be “dev” or whatever value you need.

Repeat the above steps for other environments (i.e. QA, Prod,..etc)

Click “Add an activity” next to the case statement (e.g. dev)

Drop an activity where it says “Drop activity here”, you can use an Assign activity from the primitive group to initialize certain path

When done, check in the template

Create a new build definition

Under the Process tab, choose your customized template

Notice that you can see your new argument as a parameter

Categories: Team Build, TFS, TFS2010 Tags: , ,

TFS2010: Retrieve Associated Workitems to Changesets TFS API


How to Retrieve Workitems Associated to Changesets in TFS using C# and VB.net

You need to add the following references

Microsoft.TeamFoundation.Client.dll

Microsoft.TeamFoundation.VersionControl.Client.dll

Microsoft.TeamFoundation.WorkItemTracking.Client.dll

They are located at “C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\” on my Windows 7 instance


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var changeset = GetChangeset(new Uri("http://win7-pc:8080/tfs/defaultcollection"), 21);
            foreach (var w in changeset.WorkItems)
            {
                Console.WriteLine("WorkItemId:" + w.Id);
                Console.WriteLine("WorkItemTitle:" + w.Title);

            }
            Console.ReadLine();
        }

        private static Changeset GetChangeset(Uri serverUri, int changesetId)
        {
            var tfs = new TfsTeamProjectCollection(serverUri);
            var svc = tfs.GetService<VersionControlServer>();
            var changeset = svc.GetChangeset(changesetId);

            return changeset;
        }
    }
}

 

Imports Microsoft.TeamFoundation.VersionControl.Client
Imports Microsoft.TeamFoundation.Client
Imports Microsoft.TeamFoundation.WorkItemTracking.Client

Module Module1

    Sub Main()

        Dim changeset As Changeset = GetChangeset(New Uri("http://win7-pc:8080/tfs/defaultcollection"), 21)
        For Each w As WorkItem In changeset.WorkItems
            Console.WriteLine("WorkItemId:" & w.Id)
            Console.WriteLine("WorkItemTitle:" & w.Title)
        Next

        Console.ReadLine()

    End Sub

    Function GetChangeset(ByVal serverUri As Uri, ByVal changesetId As Integer) As Changeset
        Dim tfs As TfsTeamProjectCollection = New TfsTeamProjectCollection(serverUri)
        Dim svc = tfs.GetService(Of VersionControlServer)()
        Dim changeset As Changeset = svc.GetChangeset(changesetId)

        Return changeset
    End Function
End Module

Categories: .NET, C#, TFS, TFS2010, VB Tags: , , ,

Customize Binaries Folder in TFS Team Build Part-2


In this post I will go through a different way to accomplish what I posted in Part-1. Actually this approach is way simpler and less error prone than the first one.

I will create a new configuration named TFS, change the output path for each project for that configuration to  SolutionPath\bin\Projectname, Create a team build project and update Team build template.

Create a New Configuration

We want to create a new configuration for TFS team build and we don’t want to change the Release or Debug configurations. To do so

  • Right click on the solution
  • Click configuration manager menu

  • From the “Active solution configuration” drop down select <New…>

  • Type TFS in the name textbox
  • Select the configuration to copy configuration from (e.g. Release, or debug)
  • Click OK

  • In the Solution configuration, I am changing the Active Solution Platform to Mixed Platform because the projects in the solutions are targeting different platforms

  • Click Close

Preparing the Projects in the Solution

The following steps will change the output path from bin folder to SolutionPath\bin. I my solution I had a webApplication and a windowsApplication

  • Make sure that the TFS Configuration is selected
  • Change the Output location for each project on the solution to ..\bin\ProjectName.
    • Right click on the projectà properties
    • Click the build tab
    • Fill the “output path” textbox with ..\bin\ProjectName

  • Build the solution to make sure it is working

  • Check in the solution

Create a new Team Build

  • Open Team Explorer
  • Right click on the Builds node
  • Create a new Build, I named it CustomizeBinariesFolder
  • In the Process Tab
  • Expand Items to build
  • Select the solution we configured above
  • Expand Items to build
  • Click the ellipsis next Configurations to Build

  • Type TFS under Configuration and the Platform of that configuration
  • Fill the other fields as you want

Create new Team Build Template

  • Edit your Team Build Definition
  • Go to the process tab
  • Under Build Process Template click the New… button
  • Select an existing template that you want to copy, I am selecting the DefaultTemplate
  • Name the new File
  • Click OK

  • Save the definition
  • Open Source Control from Team Explorer
  • Get latest from BuildProcessTemplates

  • Open CustomizeFolderTemplate.xaml
  • Find “Run MSBuild for Project” Activity under “Try to Compile the Project” block.
  • Clear the OutDir property

  • OutDir property over writes the default output path on each project. By Clearing the OutDir property for the MsBuild Activity, Team build will use the Output Path defined in the project. In my case, C:\Builds\{AgentNumber}\Lajak\CustomizedBinariesFolder\Sources\WindowsFormsApplication1\bin
  • Now we want to copy the contents of the bin folder from the above path (i.e. solutionPath\bin) to the binaries folder
  • Add Copy Directory Activity under Run MsBuild for Project

  • Change the Source Property to IO.Path.Combine(IO.Path.GetDirectoryName(localProject), “bin”), which means, Path of solution file + “\” + bin. By using the combine method we don’t have to worry about the Locale of the machine
  • Change the Destination property to BinariesDirectory
  • Save the Template
  • Go to Source Control Explorer and Check in the Template
  • Run the Team build definition that uses the template you have just modified. I am building the CustomizedBinariesFolder Definition


Customize Binaries folder in TFS Team Build Part 1


A new approach is posted here

Requirements

  • Output binaries must have the following structure

    –Binaries folder

    —-(Build configuration)

    ——–(Project name)

    ————-Binaries files

Issues

The default build template has few limitations that required some customization to meet our requirements. The following are the limitations found:

  • The workflow treats a solution as single project
  • The output of building projects in a solution doesn’t follow the same output directory structure when building in visual studio. For instances, web applications output binaries in the Bin folder while ClassLibrary and Windows applications projects output binaries into the Bin\(configuration) folder.
  • In visual studio, binaries are copied to a bin/(configuration) folder where “configuration” is the configuration of the build (e.g. debug, release..etc) whereas the team build outputs all binaries into one folder called Binaries and that folder doesn’t contain sub folders per project

Solution

I know of two ways to customize the binaries folder. First solution is to modify build template to:

  • Create a folder per project in the solution in the output folder
  • Copy the binaries from the bin folder of each project

Second solution:

  • Modify each project in the solution to output binaries into a common bin folder e.g $(SolutionDirectory)\Bin\$(Configuration)\$(ProjectName)
  • Team build to copy the contents of the bin folder to the binaries folder

This article is a walkthrough for solution 1. I will blog about the second solution in a different post

Modification to Projects

Assume we have the following projects in a solution:

  • Make the Output path for all projects to be the same for all configurations (e.g. debug, release …etc)

Creating new Team Build Workflow Definition

  • Create new Teambuild definition
  • Fill the necessary fields
  • Click on Process on the left
  • Show Details
  • Click the New button
  • Click browse next to “Select the file to copy”
  • Select the Default Template
  • Give it a name

  • Click OK
  • Fill the other fields you need. Make sure you select a configuration for the solution you are selecting
  • Save the build template
  • Browse to the BuildProcessTemplates folder
  • Get latest version of the template we just created

Changes to the Default Template to Meet the Requirements

  • Open the CustomBinariesFolderTemplate.xaml workflow xaml file created in the previous section
  • Click Collapse All

  • Expand On Agent

  • Expand the follow activities:
    • Try Compile, Test, and Associate Changesets and Work Items
    • Sequence
    • Compile, Test, and Associate Changesets and Work Items
    • Try Compile and Test
    • Compile and Test
    • For Each Configuration in BuildSettings.PlatformConfigurations
    • Compile and Test for Configuration
    • If BuildSettings.HasProjectsToBuild
    • For Each Project in BuildSettings.ProjectsToBuild
    • Try to Compile the Project
    • Compile the Project
  • Select MSBuild Activity
  • Set the OutDir property to “”

  • Remember we want to output the binaries into the Binaries folder\Configuration\projectFolder\
  • Add a CreateDirectory Activity under “RunMsBuild for Project”
  • Set the DisplayName property
  • Set the Directory property to

    IO.Path.Combine(BinariesDirectory, platformConfiguration.Configuration)

  • Add FindMatchingFiles activity

  • Set the MatchPatter property to IO.Path.Combine(IO.Path.GetDirectoryName(localProject),“**\*.csproj”). If you want to files of different types you need to use the following syntax:

    IO.Path.Combine(IO.Path.GetDirectoryName(localProject), “**\*.vbproj”) & “;” & IO.Path.Combine(IO.Path.GetDirectoryName(localProject), “**\*.csproj”)

  • Set the Results property to VSProjects. Notice that you will get the Error icon because VSProjects doesn’t exist. Make sure you have the Find Project files activity selected when you are adding the variable to make sure the variable is created in the appropriate scope
  • Create a new variable called VSProjects of type IEnumarable<string> ie IEnumarable(Of String)

  • Add ForEach<String> project found activity, a loop to create a folder in the binaries directory for each project found and then copy the contents of the bin/configuration or bin folder to that created folder below the binaries folder

  • Add a Create directory activity with the following code in the Directory property

    Path.Combine(BinariesDirectory, platformConfiguration.Configuration, Path.GetFileNameWithoutExtension(item))

  • Add a copy directory activity

  • Change the destination and the source properties to copy the files in the bin folder of in the source folder to the Binaries\project folder\ directory

  • Save the work flow build template and check in the template

  • Queue a build
  • When build is complete go to the binaries folder and notice that you have three folders, one per project.

Categories: Team Build, TFS, TFS2010 Tags: , ,