How to Associate an work item as "Associate" or "Resolve" in Visual Studio TFS API (VS2015)?
Asked Answered
D

3

15

I have forked a project with the code below:

var pc = ParentSection.GetService<IPendingChangesExt>();

var model = pc.GetType().GetField("m_workItemsSection", BindingFlags.NonPublic | BindingFlags.Instance);
var t = model.FieldType;
var mm = model.GetValue(pc);

var m = t.GetMethod("AddWorkItemById", BindingFlags.NonPublic | BindingFlags.Instance);

m.Invoke(mm, new object[] { selectedWorkItemId });

That adds an work item by its ID to the current pending changes.

Now, I want to link the work items choosing between "Associate" or "Resolve" (associate and resolve), depending on which button the user clicked on plugin's interface as below: enter image description here

If the user clicks on 'Associate and resolve', the work item should be associated and marked as resolved upon check-in.

If the user clicks on 'Associate only' the work item must be only linked to changeset, but not resolved.

Any help will be welcome

Doorn answered 8/3, 2016 at 17:58 Comment(0)
D
1

Look, I've accomplished it, but I KNOW it's wrong:

After including the work item using the code on the question:

IPendingChangesExt pendingChangesExt = ParentSection.GetService<IPendingChangesExt>();

var workItemSection = pendingChangesExt.GetType().GetField("m_workItemsSection", BindingFlags.NonPublic | BindingFlags.Instance);

var modelType = workItemSection.FieldType;
var model = workItemSection.GetValue(pendingChangesExt);

var m = modelType.GetMethod("AddWorkItemById", BindingFlags.NonPublic | BindingFlags.Instance);                

m.Invoke(model, new object[] { selectedWorkItemId });

I've added some new code (those are different functions, ok?) ... this second call will wait for the work item appears on the Pending Changes 'Related Work Items' section, and will change its association from Resolve to Associate 'manually'.

IPendingChangesExt pendingChangesExt = ParentSection.GetService<IPendingChangesExt>();

var model = pendingChangesExt
                     .GetType()
                     .GetField("m_workItemsSection", BindingFlags.NonPublic | BindingFlags.Instance);

var modelType = model.FieldType;
var workItemSection = model.GetValue(pendingChangesExt);

var selectedWil = workItemSection
                              .GetType()
                              .GetProperty("SelectedWorkItems")
                              .GetValue(workItemSection) as ObservableCollection<WorkItemValueProvider>;

var availablWil = workItemSection
                              .GetType()
                              .GetProperty("WorkItemsListProvider")
                              .GetValue(workItemSection) as WorkItemsListProvider;

// Waiting for section to be ready to start association
while (!availablWil.WorkItems.Where(x => x.Id == selectedWorkItemId).Any())
{                    
    await System.Threading.Tasks.Task.Delay(25);
}

selectedWil.Clear();
selectedWil.Add(availablWil.WorkItems.Where(x => x.Id == selectedWorkItemId).First());

EnvDTE80.DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2;
dte2.ExecuteCommand("TeamFoundationContextMenus.WorkItemActionLink.TfsContextPendingChangesPageWorkItemActionLinkAssociate");

selectedWil.Clear();

Despite the effectiveness of this code, I'm still working for a better solution on running the second method. The 'default value' suggested on comments will not work, because the developer should be able to associate/resolve on choosing a button, only.

Doorn answered 11/3, 2016 at 18:48 Comment(0)
R
38

This is not a property of WorkItem. This is the Check-in action on the work item. Details you can refer this link Changing the Default CheckIn Option to Associate in TFS 2012

You may need to use CheckinWorkItemAction Enumeration. More detail info from MSDN.

Similar question about TFS - VS Extension: Add work item to pending changes via API and also check this link: C# Programmatically Checking in code changes with TFS API while associating the changeset to a Work Item


Update

If you want to change the default state 'resolve' to 'associate', you need to

  • change the set the registry key HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\1x.0\TeamFoundation\SourceControl\Behavior\ResolveAsDefaultCheckinAction to False.

  • Or For VS2015, there is an option Tools > Options > Source Control > Visual Studio Team Foundation > "Resolve associated work items on check-in".

enter image description here

Note: Both of above only affects your client machine.

Otherwise, for all users, you need to edit the Work Item Template definition for the types of work items you are using (Bug, Task, etc.). Details steps you can refer this question How to disable auto done status for task in checkin

Rainproof answered 9/3, 2016 at 10:42 Comment(6)
That's right, it's not about the work item, but its association with the current changeset ... I just don't know how to touch this association, where it is and how to change its contents.Photoreceptor
Did you mean you want to implement drag & drop for the Related Work Items section of the Pending Changes Window?Take a look at this question: #25332371 and also this link social.msdn.microsoft.com/Forums/vstudio/en-US/…Rainproof
No @patrick-msft, I saw those links and they are awesome, in fact, I learnt a lot from them but the question is not that. I need to, when associating the work item, mark the association state to 'Associate' instead of 'Resolve' ... In some cases, my plugin will associate as 'resolve', in other as 'associate', I want to know how.Photoreceptor
Well, I'm not sure why your state changes. But if you want to change the default state 'resolve' to 'associate', you need to change the set the registry key HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\1x.0\TeamFoundation\SourceControl\Behavior\ResolveAsDefaultCheckinAction to False. This only works for your client. or For VS2015, there is an option > Source Control > Visual Studio Team Foundation > "Resolve associated work items on check-in". Otherwise, for all users, need to edit the Work Item Template definition for the types of work items you are using (Bug, Task, etc.).Rainproof
First, thanks for your attention @PAtrick-MSFT, your inputs have been crucial. I've improved a bit my question, in a attempt to explain myself better. My point is: Be able to choose when associate only, or associate and mark as resolved, on my plugin.Photoreceptor
The Tools > Options option still works as of Visual Studio 2019.Fining
L
3

There is only one link type between Work Item and Changeset and the link information is stored in work item. The difference between "Associate" and "Resolve" in Visual Studio is that "Associate" only link the work item to changeset while "Resolve" will change the status of the work item to "Resolved" after linking the work item to changeset.

If you are developing your own plugin, you need to write code to achieve these features manually.

Following code shows how to link a work item to a changeset:

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

namespace APPI
{
    class Program
    {
        static void Main(string[] args)
        {
            string url = "http://xxx.xxx.xxx.xxx:8080/tfs/DefaultCollection";
            TfsTeamProjectCollection ttpc = new TfsTeamProjectCollection(new Uri(url));
            WorkItemStore wis = ttpc.GetService<WorkItemStore>();
            VersionControlServer vcs = ttpc.GetService<VersionControlServer>();
            int wid = 82;
            int cid = 332;
            WorkItem wi = wis.GetWorkItem(wid);
            Changeset cs = vcs.GetChangeset(cid);
            ExternalLink el = new ExternalLink(wis.RegisteredLinkTypes["Fixed in Changeset"], cs.ArtifactUri.AbsoluteUri);
            wi.Links.Add(el);
            wi.Save();     
        }
    }
}
Laveta answered 10/3, 2016 at 9:16 Comment(2)
Eddie, very nice ... this code links a workitem with an existent changeset, previously checked in. In my case, I am setting up a commit. My plugin, as the image shows, operates on pending changes and it's supposed to mark items to be resolved (or not) before the check in is made. Thank you for your input, by the way.Photoreceptor
@EduardoEliasSaléh Just as I mentioned in the answer, you need to write code to update the state of the work item. So you can set your code to do it before or after the check in is made. However, I would recommend you to update the work item state after check in because if you changing the status to resolve before check in, the pending change is only in your local machine but the work item in server has been updated. This does not make sense. A general flow for this is: check in the pending change and then associate the workitem to the changeset and update its state if needed.Laveta
D
1

Look, I've accomplished it, but I KNOW it's wrong:

After including the work item using the code on the question:

IPendingChangesExt pendingChangesExt = ParentSection.GetService<IPendingChangesExt>();

var workItemSection = pendingChangesExt.GetType().GetField("m_workItemsSection", BindingFlags.NonPublic | BindingFlags.Instance);

var modelType = workItemSection.FieldType;
var model = workItemSection.GetValue(pendingChangesExt);

var m = modelType.GetMethod("AddWorkItemById", BindingFlags.NonPublic | BindingFlags.Instance);                

m.Invoke(model, new object[] { selectedWorkItemId });

I've added some new code (those are different functions, ok?) ... this second call will wait for the work item appears on the Pending Changes 'Related Work Items' section, and will change its association from Resolve to Associate 'manually'.

IPendingChangesExt pendingChangesExt = ParentSection.GetService<IPendingChangesExt>();

var model = pendingChangesExt
                     .GetType()
                     .GetField("m_workItemsSection", BindingFlags.NonPublic | BindingFlags.Instance);

var modelType = model.FieldType;
var workItemSection = model.GetValue(pendingChangesExt);

var selectedWil = workItemSection
                              .GetType()
                              .GetProperty("SelectedWorkItems")
                              .GetValue(workItemSection) as ObservableCollection<WorkItemValueProvider>;

var availablWil = workItemSection
                              .GetType()
                              .GetProperty("WorkItemsListProvider")
                              .GetValue(workItemSection) as WorkItemsListProvider;

// Waiting for section to be ready to start association
while (!availablWil.WorkItems.Where(x => x.Id == selectedWorkItemId).Any())
{                    
    await System.Threading.Tasks.Task.Delay(25);
}

selectedWil.Clear();
selectedWil.Add(availablWil.WorkItems.Where(x => x.Id == selectedWorkItemId).First());

EnvDTE80.DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2;
dte2.ExecuteCommand("TeamFoundationContextMenus.WorkItemActionLink.TfsContextPendingChangesPageWorkItemActionLinkAssociate");

selectedWil.Clear();

Despite the effectiveness of this code, I'm still working for a better solution on running the second method. The 'default value' suggested on comments will not work, because the developer should be able to associate/resolve on choosing a button, only.

Doorn answered 11/3, 2016 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.