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));
}
Related
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?
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.
Is there a way, either via a query or programmatically, to identify all TFS Changesets that are NOT linked to a Work Item?
Using the TFS PowerToy's PowerShell module:
From whatever folder in your workspace you're interested in:
Get-TfsItemHistory . -Recurse | Where-Object { $_.WorkItems.Length -eq 0 }
This will get the history for the current folder and all subfolders, and then filter for empty workitem lists.
Sure, you can use the TFS API to do this very easily.
public static void GetAllChangesetsWithNoWorkItems()
{
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://tfs2010/tfs/default"));
var service = tfs.GetService<VersionControlServer>();
var histories = service.GetBranchHistory(new ItemSpec[] { new ItemSpec(#"$/ProjectName/MAIN/BUILD", RecursionType.OneLevel) }, VersionSpec.Latest);
foreach (BranchHistoryTreeItem history in histories[0])
{
var change = service.GetChangeset(history.Relative.BranchToItem.ChangesetId, true, true);
if(change.WorkItems.ToList().Count == 0)
{
Debug.Write(String.Format("Work Item Missing for Changeset {0}", change.ChangesetId));
}
}
}
You can read this blog post on how to connect to TFS API Programmatically http://geekswithblogs.net/TarunArora/archive/2011/06/18/tfs-2010-sdk-connecting-to-tfs-2010-programmaticallyndashpart-1.aspx
I don't know about Richard's Answer but the accepted answer took almost 2 minutes to run from the root of my team project collection. This runs in 10 seconds if you are looking for a specific user, 47 seconds if you aren't.
service.QueryHistory("$/TeamProject/", VersionSpec.Latest,0, RecursionType.Full,userName,null,null, Int32.MaxValue,true,false)
.Cast<Changeset>()
.Where(cs=>cs.AssociatedWorkItems.Length==0)
if you aren't looking for a specific user just set userName to null
http://share.linqpad.net/6sumno.linq
I'm working on a TFS utility that gets the changesets for a particular project in TFS. I've got a home TFS 2010 server which I primarily use for testing, but I decided to give it a try against a codeplex project to which I contribute. That way, I can test functionality against a larger number of changesets than I have locally.
While it works fine in my environment, heading out over the wire to codeplex has left me stumped. My application queries the history, but then, when trying to iterate through the history (which is when it lazy-loads the IEnumerable), my application hangs.
Looking at Intellitrace, I see a couple of "first chance" exceptions that the "item doesn't exist at the specified version"-- which is patently not true, as I'm trying to get history for "$/" at VersionSpec.Latest.
I also see two or three consecutive server 500 errors being returned to me after forcing debugging to pause.
Other operations (like GetItems() ) work fine, so I'm pretty sure authentication isn't an issue.
Any thoughts?
Here's the code:
IEnumerable items = vcs.QueryHistory("$/", VersionSpec.Latest, 1, RecursionType.None, null, null, null, 5, true, false);
List<ChangesetItem> returnList = new List<ChangesetItem>();
foreach (Changeset cs in items) //hangs here on first iteraiton
{
ChangesetItem newItem = new ChangesetItem()
{
ChangesetId = cs.ChangesetId,
//ChangesetNote = cs.CheckinNote.Values[0].Value,
Comment = cs.Comment,
Committer = cs.Committer,
CreationDate = cs.CreationDate
};
returnList.Add(newItem);
}
Doh! Found it. The problem was on my QueryHistory call:
IEnumerable items = vcs.QueryHistory("$/",
VersionSpec.Latest,
1, // the deletionId should be '0' or a unique deletion identifier
RecursionType.None,
null,
null,
null,
5,
true,
false);
I commented the line of code above. For some reason, I thought deletionId was supposed to be '1', however, now that I've looked at the API, I realize that it is supposed to be a zero (for existing files), or the specific deletion Id for files that have been deleted. Apparently, the API was looking for a file with deletionId of '1', which it couldn't find, thus causing the crash.
I need to know what changes (if any) have happened at a particular level in our source control tree. Is there some way to make such a query of TFS?
Using Team Explorer:
Open Source Control Explorer
Navigate to desired source control folder
Right-click and choose View History
Shows you all of the changesets that have been checked in at that level in the tree or below.
Using the tf utility:
tf history c:\localFolder -r -format:detailed
Here's a link to the tf history documentation for more details on usage: link
Using the TFS SDK to do it programatically:
Here's a sample method based on some of our code. It takes a path, start time and end time and gives you all of the changeset details below that path in between the two specified times:
private StringBuilder GetTfsModifications(string tfsPath, DateTime startTime, DateTime endTime)
{
StringBuilder bodyContent = new StringBuilder();
TeamFoundationServer tfs = new TeamFoundationServer("YourServerNameHere");
VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
// Get collection of changesets below the given path
System.Collections.IEnumerable changesets = vcs.QueryHistory(
tfsPath,
VersionSpec.Latest,
0,
RecursionType.Full,
null,
new DateVersionSpec(startTime),
new DateVersionSpec(endTime),
int.MaxValue,
true,
false);
// Iterate through changesets and extract any data you want from them
foreach (Changeset changeset in changesets)
{
StringBuilder changes = new StringBuilder();
StringBuilder assocWorkItems = new StringBuilder();
// Create a list of the associated work items for the ChangeSet
foreach (WorkItem assocWorkItem in changeset.WorkItems)
{
assocWorkItems.Append(assocWorkItem.Id.ToString());
}
// Get details from each of the changes in the changeset
foreach (Change change in changeset.Changes)
{
changes.AppendLine(string.Format(CultureInfo.InvariantCulture, "\t{0}\t{1}",
PendingChange.GetLocalizedStringForChangeType(change.ChangeType),
change.Item.ServerItem));
}
// Get some details from the changeset and append the individual change details below it
if (changes.Length > 0)
{
bodyContent.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}\t{1}\t{2}\t{3}\t{4}",
changeset.ChangesetId,
changeset.Committer.Substring(changeset.Committer.IndexOf('\\') + 1),
changeset.CreationDate,
changeset.Comment,
assocWorkItems.ToString()));
bodyContent.Append(changes.ToString());
}
}
return bodyContent;
}
If I understand correctly, the answer could be as simple as:
tf history c:\some\subdir -r -format:detailed -noprompt
Reply if that's not good enough.