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.
Related
I'm not sure I have a specific question other than--have other people seen this? And if so, is there a known workaround / fix? I have failed to find anything on Google on this topic.
Basically, we have an ASP.NET MVC application that we run on localhost that extensively uses the ASP.NET in memory cache. We cache many repeated requests to the Db.
Yesterday, we upgraded two of our dev machines to Windows 10 Creators Update. After that update, we noticed that the page requests on just those machines started to craw. Upwards of 30 seconds per page.
After some debugging and viewing logs, we are seeing that the system is making the same request to the Db 200-300 times per request. Previously, this would just be cached the first time, and that request would not happen again until the cache expired it.
What we are seeing is that this code:
var myObject = LoadSomethingFromDb();
HttpRuntime.Cache.Insert("test", myObject);
var test = HttpRuntime.Cache.Get("test");
at some point, the Get would be returning NULL even if it is right after the Insert in code and even though there is no way the cache is even close to full. The application is just starting.
Anybody else see this?
Nevermind. We got bit by the Absolute Cache Expiration parameter which I neglected to include in the question's code because I didn't think that was relevant.
We were using an absolute cache expiration of:
DateTime.Now.AddMinutes(60)
instead, we should have been using:
DateTime.UtcNow.AddMinutes(60)
Not sure why the former was fine in Windows prior to Creator's Update, but the change to UtcNow seems to make the cache work again.
It appears that after the windows creators update that the behavior of cache.Insert overload methods behave differently.
[Test]
public void CanDemonstrateCacheExpirationInconsistency()
{
var cache = HttpRuntime.Cache;
var now = DateTime.Now;
var key1 =$"Now{now.Ticks}";
var key2 = key1+"2";
var key3 = $"UtcNow{now.Ticks}";
var key4 = key3 + "2";
cache.Insert(key1, true, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
cache.Insert(key2, true, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration,CacheItemPriority.Default,null);
cache.Insert(key3, true, null, DateTime.UtcNow.AddHours(1), Cache.NoSlidingExpiration);
cache.Insert(key4, true, null, DateTime.UtcNow.AddHours(1), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
Assert.That(cache.Get(key1), Is.Null); //Using this overload with datetime.now expires the cache immediately
Assert.That(cache.Get(key2), Is.Not.Null);
Assert.That(cache.Get(key3), Is.Not.Null);
Assert.That(cache.Get(key4), Is.Not.Null);
}
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 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));
}
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);
// ...
}
I was hoping that I could pass a DateVersionSpec into VersionControlServer.DownloadFile() but it doesn't work. It tells me that the item doesn't exist at that version, even though the file existed in source on the date passed.
Do I need to query the Item history just so I can figure out what version the file was at on the date in question? Use QueryHistory(...) method?
My current code:
version = new DateVersionSpec(date);
var changeSets = this.vcServer.QueryHistory(remoteFile, VersionSpec.Latest, 0,
RecursionType.None, user, version, version, 50, true, false);
if (changeSets == null)
{
throw new Exception("Failed to find...");
}
foreach (var item in changeSets)
{
}
Currently I'm not getting anything back when I pull the changeSets enumerable.
I'm using code that's a lot like this: http://blogs.microsoft.co.il/blogs/srlteam/archive/2009/06/14/how-to-get-a-file-history-in-tfs-source-control-using-code.aspx
Update: the code that I have is pretty close (practically identical to the code from the post) but it dies if the file was added on a date before the date passed in and hasn't been changed since i.e. it only has one change and that's an add.
This got me what I was looking for on my app. If it doesn't work check to make sure your file path is correct. That's what I had wrong the first time around.
this.vcServer.GetItem(remoteFile, new DateVersionSpec(date));