Blogger Widgets
  • Sharing Photos using SignalR
  • TFS Extenstion - allows copy work items between projects
  • Displaying jquery progressbar with ajax call on a modal dialog
  • Managing windows services of a server via a website
  • Exploring technologies available to date. TechCipher is one place that any professional would like to visit, either to get an overview or to have better understanding.

Search This Blog

Thursday, 24 May 2012

TFS Helper package extension for Visual Studio 2010

VS2010 is well integrated to TFS and has all the features required on day to day basis. Most common feature any developer use is managing workitems. Creating work items is very easy as is copying work items, but what I need is to copy workitem between projects retaining links and attachments. I am sure this is not Ideal and against sprint projects.

I have created a Visual Studio Package that can achieve this. Here is the step-by-step guide

1. Using VS2010 create a project of type "Visual Studio Package"

2. Select language as "C#" and select "Next"

3. Specify package information and select "Next"
4. Now select "Menu Command" and "Tool Window" and select "Next"
5. Specify command options, tool window options and select "Next"
6. De-select test project options and select "Finish". Now we have completed creating a new package project.
7. Add TFS references to the project
8. Make following code changes
VS2010.TFSHelperPackage.GuidList Class
..
public const string guidVSPackage1CmdSetString2 = "6E282364-7C4B-4E12-868D-AC8572708416";
..
public static readonly Guid guidVSPackage1CmdSet2 = new Guid(guidVSPackage1CmdSetString2);
..

VS2010.TFSHelperPackage.PkgCmdIDList Class
..
public const uint cmdidCopyWorkItemAdvanced = 0x100;
..
TFSHelperPackage Class -> Initialize()
protected override void Initialize()
        {
....
 // Create the command for the menu item.
CommandID menuCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet2, (int)PkgCmdIDList.cmdidCopyWorkItemAdvanced);
MenuCommand menuItem2 = new MenuCommand(CopyWorkItemAdvancedCallback, menuCommandID2);
mcs.AddCommand(menuItem2);
..
}
private void CopyWorkItemAdvancedCallback(object sender, EventArgs e)
{}


Update "TFSHelperPackage.vsct"

 
  
     ....
      
        
      

    
 
....



..



...

    

      
      
    
...

      
    
...


Now GuidSymbol name="guidTFSContextMenu" is very important as value "517" is the id for "Results List" menu item. Refer to Using EnableVSIPLogging to identify menus and commands with VS 2005 + SP1 to find out Menu command Id/GUIDs.
9. Add a new windows form as follows

10. Now update CopyWorkItemAdvancedCallback with following code
private void CopyWorkItemAdvancedCallback(object sender, EventArgs e)
        { using(CopyWorkItemAdvancedForm cw = new CopyWorkItemAdvancedForm(this))
           {
               if(cw.ShowDialog() == System.Windows.Forms.DialogResult.OK)
               {
                   cw.Close();
               }
           }
        }

11. Update CopyWorkItemAdvancedForm code behind as follows
public partial class CopyWorkItemAdvancedForm : Form
    {
        private IServiceProvider _serviceProvider;
        private IWorkItemTrackingDocument _currentDocument;
        private WorkItem _currentWorkItem;
        private WorkItem _newWorkItem;
        private WorkItemStore _workItemStore;

        public CopyWorkItemAdvancedForm(IServiceProvider serviceProvider)
        {
            InitializeComponent();
            _serviceProvider = serviceProvider;
            LoadControls();
        }

        private void LoadControls()
        {
            this.cmbProjects.Items.Clear();
            this.cmbWorkItemTypes.Items.Clear();

            //Load source workitem 
            _currentDocument = WitDocumentHelper.GetCurrentWitDocument(_serviceProvider);
            string selectedItemId = string.Empty;
            if (_currentDocument is IResultsDocument)
            {
                int cnt = ((IResultsDocument)_currentDocument).SelectedItemIds.Length;
                if (cnt > 0)
                {
                    IResultsDocument resultDocument = (IResultsDocument)_currentDocument;
                    selectedItemId = resultDocument.SelectedItemIds[0].ToString();
                    _currentWorkItem = resultDocument.ResultListDataProvider.GetItem(0);
                }
            }
            else if (_currentDocument is IWorkItemDocument)
            {
                // To be completed
            }
            else if (_currentDocument is IQueryDocument)
            {
                // To be completed
            }
            else
            {
                // To be completed
            }

            this.Text = "Create Copy of Work Item with options ... [ " + selectedItemId + "]";

            //Load dropdowns
            var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
            TeamFoundationServerExt ext = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt") as TeamFoundationServerExt;
            TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(ext.ActiveProjectContext.DomainUri));

            // Refer to http://msdn.microsoft.com/en-us/library/bb286958.aspx for list of types available with GetService
            _workItemStore = teamProjectCollection.GetService();

            if (_workItemStore != null)
            {
                if (_workItemStore.Projects.Count > 0)
                {
                    foreach (Project prj in _workItemStore.Projects)
                    {
                        this.cmbProjects.Items.Add(prj.Name);

                        if (this.cmbWorkItemTypes.Items.Count == 0)
                        {
                            foreach (WorkItemType wtype in prj.WorkItemTypes)
                            {
                                string wtypeName = wtype.Name;
                                if (!this.cmbWorkItemTypes.Items.Contains(wtypeName))
                                    this.cmbWorkItemTypes.Items.Add(wtypeName);
                            }
                        }

                    }
                }
            }


            this.cmbWorkItemTypes.SelectedIndex = this.cmbWorkItemTypes.Items.IndexOf(_currentWorkItem.Type.Name);
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            if (_currentWorkItem != null)
            {
                CreateNewWorkItem();
                string message = string.Format("Copied Item Successfully !!! \r\n Source Item ID {0} has {1}  Attachments and {2} Links \r\n\r\n Target Item ID {3} has {4} Attachments and {5} Links",
                    _currentWorkItem.Id,
                    _currentWorkItem.Attachments.Count,
                    _currentWorkItem.Links.Count,
                    _newWorkItem.Id,
                    _newWorkItem.Attachments.Count,
                    _newWorkItem.Links.Count);
                MessageBox.Show(message, this.Text, MessageBoxButtons.OK);
            }

            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void CreateNewWorkItem()
        {

            Project targetProject = _workItemStore.Projects[this.cmbProjects.SelectedItem.ToString()];

            WorkItemType wit = targetProject.WorkItemTypes[this.cmbWorkItemTypes.SelectedItem.ToString()];

            _newWorkItem = _currentWorkItem.Copy(wit);

            RelatedLink source2Target = new RelatedLink(targetProject.Id);
            _newWorkItem.Links.Add(source2Target);

            System.Net.WebClient request = new System.Net.WebClient();
            request.Credentials = System.Net.CredentialCache.DefaultCredentials;
            string tempPath = System.IO.Path.GetTempPath();
            if (_currentWorkItem.Attachments.Count > 0)
            {
                foreach (Attachment attach in _currentWorkItem.Attachments)
                {
                    string attachmentPath = Path.Combine(tempPath, attach.Name);
                    request.DownloadFile(attach.Uri, attachmentPath);
                    _newWorkItem.Attachments.Add(new Attachment(attachmentPath));

                }
            }
            _newWorkItem.Save(SaveFlags.MergeLinks);

        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }
    }

12. Also add a new helper class WitDocumentHelper
 class WitDocumentHelper
    {

        public static IWorkItemTrackingDocument GetCurrentWitDocument(IServiceProvider serviceProvider)
        {
            Debug.Assert(serviceProvider != null);

            EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
            if (dte.ActiveDocument == null)
                return null; // No active document

            DocumentService docService = (DocumentService)serviceProvider.GetService(typeof(DocumentService));
            if (docService == null)
                return null; // Possibly VSTS WIT is not installed or instantiated yet.

            IWorkItemTrackingDocument doc = docService.FindDocument(dte.ActiveDocument.FullName, serviceProvider);
            return doc; // Caller must release the document after use
        }

    }

This completes the task of creating a package to copy workitem between projects. Complete source code is available on Git via codeplex at tfshelperforvs2010.codeplex.com.

All of the biggest technological inventions created by man - the airplane, the automobile, the computer - says little about his intelligence, but speaks volumes about his laziness. ~Mark Kennedy

1 comments:

Copyright © 2013 Template Doctor . Designed by Malith Madushanka - Cool Blogger Tutorials | Code by CBT | Images by by HQ Wallpapers