TFS item unique identifier - tfs

During working with TFS API, I faced the following problem.
I have two repository changesets, say A and B:
In changeset A the file 1.cs was changed
In changeset B the file 1.cs was renamed
Is there a way to find out that files with different names from changeset A and B are in fact the same file that was renamed? I thought I could use ItemId from Item properties list but for some reason its different.
Here is some sample, which demonstrates the issue:
var changeset = versionControl.GetChangeset(changesetA);
var changeItemA = changeset.Changes.Single(i => i.Item.ServerItem == "1.cs");
var changeset = versionControl.GetChangeset(changesetB);
var changeItemB = changeset.Changes.Single(i => i.Item.ServerItem == "1.cs");
// fails
Assert.Equal(changeItemA.Item.ItemId, changeItemB.Item.ItemId);
I use Microsoft.TeamFoundationServer.Client version="14.102.0" and Microsoft.TeamFoundationServer.ExtendedClient version="14.102.0" to interact with TFS (.Net 4.6.2)
Is there a unique identifier that is assigned to TFS item and that lives with it during the whole life regardless of renaming?

Related

Team Foundation Server - Backdate Epics

I am taking over a catalog of projects that already initiated. My job is to enter the projects into TFS and use the 'work' features. I am entering each project as an Epic...15 Epics total. When I enter an Epic is used the date I enter it as the project initiation day. Is there a way to grandfather in Epics in TFS. Adding Epics with a start date in the past? I cannot congigure the cumulative flow diagram properly without being able to back date entries.
Thanks
In Epics, the default field "CreateDate" can't be changed. It uses the date and time when the Epic created.
As a alternative, you can customize a field to use DateTimeControl, then you can select Date and change the time in this custom field:
There isn't any way to change the create date from TFS Web Portal. But if you create the work item via TFS API, you can enable the bypassrule which allow you specify the create date of the work item. Following is a code sample for this:
static void Main(string[] args)
{
string url = "http://collectionurl/";
TfsTeamProjectCollection ttpc = new TfsTeamProjectCollection(new Uri(url));
WorkItemStore wis = new WorkItemStore(ttpc.Name,WorkItemStoreFlags.BypassRules);
Project pro = wis.Projects["ProjectName"];
WorkItemTypeCollection wits = pro.WorkItemTypes;
WorkItem wi = new WorkItem(wits["Epic"]);
wi.Fields["System.Title"].Value = "Title";
wi.Fields["System.CreatedDate"].Value = Convert.ToDateTime("2016-09-01");
wi.Save();
}
Note: To use this, you must be the member of "Project Collection Administrators" security group.
Refer to this link for details: TFS API Part 48 – WorkItemControl And Bypass Work Item Rules.

Access the Kanban Column (a Team-Specific Field) for a Work Item

Is there a way to programmatically access the "Kanban Column" for a WorkItem using the TFS 2012 API?
Using the Scrum 2.2 template, the history of a Bug or Product Backlog Item shows "[MyProject\MyTeam] Kanban Column" as a changed field whenever a work item is dragged between Kanban columns on the Board, but the field is not accessible when specifically retrieving a work item through the TFS API.
It also shows up as a changed field in the WorkItemChangedEvent object when implementing the ProcessEvent method on the Microsoft.TeamFoundation.Framework.Server.ISubscriber interface.
Workaround:
A coworker found a blogpost about creating a read-only custom field to persist the value of the Kanban Column, taking advantage of the WorkItemChangedEvent to capture the latest value. It is then possible to query on this column. One problem with this approach is that only a single team's Kanban Column can be tracked.
Update:
According to this blogpost, the Kanban Column is not a field, rather a "WIT Extension". This may help lead to an answer.
I've found a way to read the value using the TFS 2013 API, inside the ISubscriber.ProcessEvent method:
var workItemId = 12345;
var extService = new WorkItemTypeExtensionService();
var workItemService = new WorkItemService();
var wit = workItemService.GetWorkItem(requestContext, workItemId);
foreach (var wef in extService.GetExtensions(requestContext, wit.WorkItemTypeExtensionIds))
{
foreach (var field in wef.Fields)
{
if (field.LocalName == "Kanban Column" || field.LocalName == "Backlog items Column")
{
// Access the new column name
var columnName = wit.LatestData[field.Field.FieldId];
}
}
}
If you are prepared to dig into the database you can mine this information out. I don't fully understand the modelling of the teams in TFS yet but first you need to work out which field id the team of interest is storing the Kanban state in as follows (TFS 2012):
USE Tfs_DefaultCollection
SELECT TOP(10)
MarkerField + 1 as FieldId,*
FROM tbl_WorkItemTypeExtensions with(nolock)
JOIN tbl_projects on tbl_WorkItemTypeExtensions.ProjectId = tbl_projects.project_id
WHERE tbl_projects.project_name LIKE '%ProjectName%
Then replace XXXXXXXX below with the FieldId discovered above
SELECT TOP 1000
wid.Id,
wia.State,
wid.StringValue as Kanban,
wia.[Work Item Type],
wia.Title,
tn.Name as Iteration
FROM tbl_WorkItemData wid with(nolock)
JOIN WorkItemsAre wia on wia.ID = wid.Id
JOIN TreeNodes tn on wia.IterationID = tn.ID
WHERE FieldId = XXXXXXXX and RevisedDate = '9999-01-01 00:00:00.000'
ORDER BY Id
I am not familiar with the Scrum 2.2 template, but the works are the same for CMMI or Scrum templates when it comes to TFS Work Item tracking.
Try something like this:
public string GetKanbanColumn(WorkItem wi)
{
if (wi != null)
{
return wi["Kanban"].ToString();
}
return string.Empty;
}
Depending on the actual name of the column, specified in the Work Item Template XML file. Hope this helps.

What tfs 2010 object references are available for Tfs_DefaultCollection.dbo.tbl_ReleaseNoteDetails

We have a Team Project Collection Source Control Setting for Check-in Notes that requires each check-in to capture a "Tracking Number". This number is external to TFS. I need to search for all the changesets that have a specific Tracking number.
The resulting changeset list tells me what to GetLatest on, for our monthly deployment.
-- We don't use Work Items
This .SQL gives me the list I'm looking for. I want to access this in code from Visual Studio.
SELECT ReleaseNoteId, FieldName, BaseValue
from Tfs_DefaultCollection.dbo.tbl_ReleaseNoteDetails
where ReleaseNoteId in (SELECT ReleaseNoteId
FROM Tfs_DefaultCollection.dbo.tbl_ReleaseNote
where DateCreated between '2013-01-01' and '2013-01-31')
and FieldName = 'Tracker #'
and BaseValue = '18570'
What object references are available for Tfs_DefaultCollection.dbo.tbl_ReleaseNoteDetails?
There is no 1to1 object reference in the TFS API, because you usually don't work on the structure like the database looks like.
What I understand from your description, you have the information you need in the changesets. In that case you could use the VersionControlServer to get the changesets and get the information from there.
TfsTeamProjectCollection tfsConnection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFS:8080/TFS/DefaultCollection"));
VersionControlServer sourceControl = (VersionControlServer)tfsConnection.GetService(typeof(VersionControlServer));
IEnumerable changesets = sourceControl.QueryHistory(ServerPath, VersionSpec.Latest, 0, RecursionType.Full, null, new DateVersionSpec (new DateTime(2013,1,1)), new DateVersionSpec (new DateTime(2013,1,31)), Int32.MaxValue, true, false);
foreach (Changeset change in changesets)
{
// check where the information is stored in the changeset, may change.Changes
}
Just an idea to get in the right direction.
If you want easy querying and searching, you're better off creating a new work item field and associate the work item during checkin. Work items have complete querying capabilities in the UI and are even transported to the Reporting warehouse.
You could retrieve the history for a specific folder, date range etc using a QueryHistoryParameters object and then iterate over the CheckinNotes to filter:
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri("http://localhost:8080/tfs/DefaultCollection"));
var versionControlServer = projectCollection.GetService<VersionControlServer>();
var query = new QueryHistoryParameters("$/Scrum/**", RecursionType.Full);
var changesets = server.QueryHistory(query);
changesets.Where(cs => cs.CheckinNotes.Any(note => note.PropertyName == "Tracker #"
&& note.Value == "18570"))
This is not going to be terribly fast. To get a quick solution, use work item association.

how to group resources involved in a specific set of changesets?

How can I query the tfs history to have this result: group the resources involved in a set of changesets?
What I'm trying to do is understanding which files changed in the last 2 months for example.
I tried on TFS Explorer, but I can obtain the details just from a single changeset. It's the same for TFS Sidekicks. I had no luck with the command line and not even connecting directly to the database.
Does someone knows a smart way to get that result?
I am not sure how to get the VersionTo and VersionFrom so I am just doing from version 100 to Latest in here. You could you Source Control Explorer to do a View History and get your VersionFrom and VersionTo.
Here's a snippet of code that uses the TFS API. You will need to add some references to Microsoft.TeamFoundation.* assemblies to get it to build.
using (var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(CollectionAddress)))
{
var server = tfs.GetService<VersionControlServer>();
var changes =
server.QueryHistory(
"$/Project/Main",
VersionSpec.Latest,
0,
RecursionType.Full,
"",
VersionSpec.ParseSingleSpec("100", ""), //From ??
VersionSpec.Latest, //To ??
100,
true,
true)
.Cast<Changeset>()
.SelectMany(changeset => changeset.Changes.Select(change => change.Item.ServerItem));
}

TFS 2010 API: Get old name/location of renamed/moved item

I'm writing an application that pulls changesets from TFS and exports a csv file that describes the latest changes for use in a script to push those changes into ClearCase. The "latest" doesn't necessarily mean the latest, however. If a file was added and then edited, I only need to know that the file was added, and get the latest version so that my script knows how to properly handle it. Most of this is fairly straight-forward. I'm getting hung up on files that have been renamed or moved, as I do not want to show that item as being deleted, and another item added. To uphold the integrity of ClearCase, I need to have in the CSV file that the item is moved or renamed, along with the old location and the new location.
So, the issue I'm having is tracing a renamed (or moved) file back to the previous name or location so that I can correlate it to the new location/name. Where in the API can I get this information?
Here is your answer:
http://social.msdn.microsoft.com/Forums/en/tfsgeneral/thread/f9c7e7b4-b05f-4d3e-b8ea-cfbd316ef737
Using QueryHistory you can find out that an item was renamed, then using its previous changeset (previous to the one that says it was renamed) you can find its previous name.
You will need to use VersionControlServer.QueryHistory in a manner similar to the following method. Pay particular attention to SlotMode which must be false in order for renames to be followed.
private static void PrintNames(VersionControlServer vcs, Change change)
{
//The key here is to be sure Slot Mode is enabled.
IEnumerable<Changeset> queryHistory =
vcs.QueryHistory(
new QueryHistoryParameters(change.Item.ServerItem, RecursionType.None)
{
IncludeChanges = true,
SlotMode = false,
VersionEnd = new ChangesetVersionSpec(change.Item.ChangesetId)
});
string name = string.Empty;
var changes = queryHistory.SelectMany(changeset => changeset.Changes);
foreach (var chng in changes)
{
if (name != chng.Item.ServerItem)
{
name = chng.Item.ServerItem;
Console.WriteLine(name);
}
}
}
EDIT: Moved the other solution up. What follows worked when I was testing against a pure Rename change but broke when I tired against a Rename and Edit change.
This is probably the most efficient way to get the previous name. While it works (TFS2013 API against as TFS2012 install), it look like a bug to me.
private static string GetPreviousServerItem(VersionControlServer vcs, Item item)
{
Change[] changes = vcs.GetChangesForChangeset(
item.ChangesetId,
includeDownloadInfo: false,
pageSize: int.MaxValue,
lastItem: new ItemSpec(item.ServerItem, RecursionType.None));
string previousServerItem = changes.Single().Item.ServerItem;
//Yep, this passes
Trace.Assert(item.ServerItem != previousServerItem);
return previousServerItem;
}
it would be used like:
if (change.ChangeType.HasFlag(ChangeType.Rename))
{
string oldServerPath = GetPreviousServerItem(vcs, change.Item);
// ...
}

Resources