Wednesday, February 13, 2008

Team Foundation Server and VSIP tidbits

One basic question that immediately comes up when writing Visual Studio Integration Package (VSIP) that needs to make use Team Foundation Server extensiblity, is how to handle TFS extensibility objects. "How to" for writing add-ins is well described in now classic blog post by Ed Hintz; while most of it applies also to VSIP there are some missing pieces that I will try to address.

As a first step, one needs to get TFS extensibility objects; once the extensibility objects are available, there is no major difference between add-in (as described in Ed's article) development and VS package.

To obtain reference to TFS specific objects (such as VersionControlExt) one needs DTE2 instance; in VSIP one may use the following approach to retrieve global DTE:

// use package GetService method to get
// extensibility service
EnvDTE.IVsExtensibility extensibility = 
   GetService(typeof(EnvDTE.IVsExtensibility)) as EnvDTE.IVsExtensibility;
// get IDE Globals object and DTE from that
EnvDTE80.DTE2 dte2 = 
   extensibility.GetGlobalsObject(null).DTE as EnvDTE80.DTE2;
            Debug.Assert(dte2 != null, "No DTE2");

Once reference to DTE2 is available, reference to TFS extensibility objects may be obtained as follows:

VersionControlExt versionControlExt = 
   dte2.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") 
   as VersionControlExt;

Another frequently asked question is how to monitor when TFS server connection status in Visual Studio IDE. There is no special event exposed for this purpose; however, ProjectContextChanged event of TeamFoundationServerExt object may be used for this purpose (see Tim Noonan's excellent post for more details on this event). When TFS server is disconnected, active project context properties become null; when connected, the values in the context can be used to get reference to TeamFoundationServer object:

private void ProjectContextChanged(object sender, EventArgs e)
{
    // server is disconnected
    if (_teamServerExt.ActiveProjectContext.DomainName == null)
        ; // do disconnected stuff
    else 
    {
        // connected, can get reference to server
        //TeamFoundationServerFactory.GetServer(
        //    _teamServerExt.ActiveProjectContext.DomainUri.ToString());                
    }
}

Tracking TFS server connection status may seem unimportant, but it becomes vital in scenarios with several TFS servers available, or where VS may be started disconnected with connection to TFS established later on. In such cases assuming that the connection is always active may lead to some ugly bugs in your package.

Wednesday, February 06, 2008

Microsoft Static Code Analysis tools survey

February issue of TFS Times newsletter is out; and this time I am personally involved since it contains a short bit I did on Microsoft Static Code Analysis tools in Visual Studio 2005/2008. Read that online or get the PDF version here.

Update: There is mirror for the article available here.

Monday, February 04, 2008

Building VS2008 projects in VS2005

Today I got reminded of one issue, that I did not mention in the previous post on VS2005 solutions and projects conversion to VS2005 (mostly because I was not aware of that at the time :).

As it is .Net projects created in VS2005 can be built both in 2005 and 2008 without any changes to the project file. However, should you create a new project in VS2008 (even one targeting .Net 2.0), you will not be able to build it in VS2005. The reason is that VS2008 project is created compliant with MSBuild 3.5, in which $(MSBuildBinPath) property (location of all system target files) is deprecated, and $(MSBuildToolsPath) is used instead. Thus VS2008 will use MSBuildToolsPath to specify the location of Microsoft.CSharp.targets file, and the project will promptly blow in VS2005 on build.

As far as I know, there is no elegant solution to this problem (short of changing the project file). Probably the easiest solution would be to create the projects in VS2005 (that is, if you want to have .Net 2.0 projects that can be opened in both versions of Visual Studio). If you do modify the project files, here is the snippet I use to make sure that the project can be built in both flavours of Visual Studio:

<!-- VS2008 original import (sans condition 

     which is added for VS2005 benefit) -->

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" 

        Condition="$(MSBuildToolsPath) != ''" />

<!-- VS2005 import - added for VS2005 compatibility 

     (since there is no ToolsPath there) -->

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" 

        Condition="$(MSBuildToolsPath) == ''" />

Footnote: once you decide to use .Net 3.5 in your project on VS2008, then obviously your project wont build in VS2005 no matter the modifications.

Tuesday, January 29, 2008

Skipping post-build in VS project in Team Build

Interesting question has come up in the forums: "If one has custom pre- or post- build logic in Visual Studio projects, that are being built both on desktop and using Team Build, how one would disable the pre-/post-build for non-desktop build?".
Or to be more concise - is there any property available that makes it possible to detect, whether the build is being performed from Visual Studio or from Team Build process?

Now, Team Build build types will simply call MSBuild task with the solution(s) to build; will Team Build pass any custom properties to MSBuild with the solution files?

It turns out that Team Build does indeed pass such property, named TeamBuildConstants; thus when the solution will be built from the Team Build script, the property will get the value of _TEAM_BUILD_, as defined in Microsoft.TeamFoundation.Build.targets file.

Then Visual Studio project (C# and VB.NET alike) can be modified in the following manner:


<!-- Prebuild logic will be executed both in VS and Team Build compilations -->
<Target Name="BeforeBuild">
    <Exec Command="attrib -r $(TargetPath)"/>
</Target>

<!-- Postbuild logic that will not be executed in Team Build-->
<Target Name="AfterBuild" Condition="'$(TeamBuildConstants)' == ''">
    <Copy SourceFiles="$(TargetPath)"
      DestinationFolder="$(SolutionDir)\bin\$(ConfigurationName)" />
</Target>

Team Build targets file also exposes property with very tempting name - SkipPostBuild; however, modifying the property value in TFSBuild.proj will have no effect on the projects post build logic. Setting SkipPostBuild property to false disables running GenCheckinNotesUpdateWorkItems task during Team Build build, and thus has no connection to Visual Studio projects logic.

Saturday, January 19, 2008

Using WIQL EVER with dates - dont!

One of very neat predicates available in Work Item Query Language is EVER conditional clause. It allows one to specify conditions similar to "was the value of the <field> ever <X>". Typical example of a query - list of all tasks ever assigned to myself:

SELECT [System.Id], [System.AssignedTo]
FROM WorkItems
WHERE [System.TeamProject] = 'Project1' AND [System.AssignedTo] EVER @me
ORDER BY [System.Id]

That feature is very convinient (saves all that ugly EXISTS queries of traditional SQL); however, it turned out it is not without its limitation.

Some time ago there was an interesting question on MSDN forums: "How one would use EVER to get work items specified at certain date?" Though MSDN says that date time fields should work with EVER operator, in reality it appears that the operator will not function correctly.

My guess is that EVER uses the exact field value to test against - and for the date time fields that includes time portion of the value. That of course limits its usefulness (while the query of whether certain work item was modified on date X is of value, nobody cares what work item was modified on date X at 12:33.56 :).

So the purpose of that post is to save you some time - do not attempt to use EVER with dates; depending on your actual objective the answer may be in WIQL or you might have to do additional filtering programmatically.

Friday, January 18, 2008

Specifying date and time in WIQL queries

When creating Work Item queries, sometimes it may be required to specify not only date, but time also for the query condition. For myself, I usually use that when I need to find all work items changed relative to certain event - for example, labeling of the source code; and as it happens, there may be several such events in one day, so the time is of importance.

The obvious solution is to specify a query similar to "Closed Date > 1/1/2008 10:00" (or in pure WIQL: [Microsoft.VSTS.Common.ClosedDate] > '2008-01-01T10:00:00.0000000').

But life is not that simple. What you get on running the query is the error message, saying "You cannot supply a time with the date when running a query using date precision. The error is caused by '[Microsoft.VSTS.Common.ClosedDate] > '2008-01-01T10:00:00.000'".

Without trying to analyze the message too much, one can surmise from it that currently only dates can be specified in query conditions, and apparently you need to change the precision from date to "date time". Easy enough, huh? So how do we change the precision?

You are in for a surprise - you cannot change the precision. If you ran the query in VS, you will always have the date precision and will not be able to specify times. However, there is sort of workaround if you are really hot for the query results. You will have to write a small bit of code (interestingly, the object model API allows one to specify the precision for the query), as demonstrated below:


TeamFoundationServer server = TeamFoundationServerFactory.GetServer("10.18.40.201");

WorkItemStore wit = new WorkItemStore(server);

stringwiql = @"SELECT [System.Id], [Microsoft.VSTS.Common.ClosedDate] 

                FROM WorkItems 

                WHERE [System.TeamProject] = 'Project1' AND 

                [Microsoft.VSTS.Common.ClosedDate] > '2008-01-01T10:00:00.00' 

                ORDER BY [System.Id]";

Query qry = new Query(wit, wiql, null, false);

ICancelableAsyncResult car = qry.BeginQuery();

WorkItemCollection items = qry.EndQuery(car);


The trick is in the fourth parameter passed to the Query class constructor (setting false specifies that date and time precision should be used instead of default date precision).

The documentation on that parameter is rather cryptic; I am not aware of any additioanl docs on WIQL precision.

While the issue is not critical, the lack of the date time precision in VS work item queries is a bit of a nuisance (as far as I know, VS2008 still suffers from that). Hope that Rosraio will handle that.

Monday, December 24, 2007

New TFS releases - in time for holidays

If you happen to have some leasure during holidays, you might want to check out the following:


While those VPC rock, one small note - the TFS server is completely bare (that is you should expect to spend some time to setup projects, build etc. if you are going to use those VPCs for demo).
And they do not have new TFS Power Tools pre-installed. What, you have not heard about it? Yes, you should download VS2008 version of Power Tools. My favorites in this version are files and status search (for all ye SourceSafe faithful, it is very similar to VSS operation - allows one to search by file name and file status) and quick label (allows labeling of the selected files/folders in one click).
And that's not all! There is also new version of MSSCCI provider for your to download!
Check Brian Harry's blog for more information.

And Happy Holidays to all! See you in 2008!

Thursday, December 13, 2007

Offline in VS 2008 (continued)

In a previous post I talked about offline story for TFS and Visual Studio 2008.

And since then, several important additions have come up.

One important note relates to what exactly becomes "offline" - solution you are opening or the whole server. It turns out that the default behavior will label the whole TFS server as being offline, and as a result, when you will open another solution (without first performing "Go online" on the first one), it will be opened offline automatically. To get the whole server back "online", you will have to perform "Go online" on one of the solutions.

And that indirectly may cause a bug that is described in the MSDN forum post - when the solution is opened from Source Control Exlorer and the server is offline, the error message will appear (though I believe the flow described will not be something often used).

The nuances of offline operation are described in Ben Ryan's blog. Additionally, if you are not happy with whole TFS server being labeled offline when single solution is taken offline, Ben also describes the way to change that behavior.

I can only add that I wish Ben Ryan would post more often (less "offline" time for the blog :)- it appears that he has lots of interesting version control stories to tell.

Wednesday, December 12, 2007

Get latest on check-out in TFS 2008 (footnote)

One of the new features in TFS 2008 is the ability to get the latest version on the check out (yes, yes, that's the very same feature that was discussed a zillion times).

The checkbox "Get latest version of item on check out" is located in "Tools->Options" menu, "Source Control->Visual Studio Team Foundation Server" settings tab.

That would be it but for the following fact - you will see the checkbox after you installed VS2008 and Team Explorer 2008, and it will be enabled no matter what TFS server you are using (2008 client will work both with 2005 and 2008 server). But it will work as advertised only if you have TFS2008 server!

So be forewarned - it took me quite some staring at the screen and googling to understand why the latest version did not appear :)

Saturday, December 01, 2007

Choices in conversion of solutions and projects to VS2008

On the weekend I am trying to catch up on my blogroll, and I have found several excellent posts on conversion between VS2005 and VS2008. Now that VS2008 is released, the conversion of code base from previous version will become a common problem, and here is some advise on dealing with that.

Of course simplest way would be just converting all solutions to VS2008 (see below why you do not have to convert projects). Here you have several choices:
- Open VS2005 solution in VS2008 and run the conversion wizard.
- Run VS2008 in command-line converting the solution in place in the background (that should be perfect if you have more than one solution :). Read more about magical command-line "/upgrade" switch in John Robbins blog post.
- Mess around with solution file in text editor. The difference between solution for VS2005 and VS2006 would be only the version specifier("Format Version 9.00" vs. "Format Version 10.00"). The difference in projects would be only MSBuild ToolsVersion attribute (that serves to define .NET toolset project is built with). Since all converted projects use 2.0, that can be easily set. Read in more detail about solution and project formats changes in DJ Park blog post.

Now, if you still need to do some development on VS2005 while doing development in VS2008 in the same solution, the best bet would be probably to create a new solution (e.g. "Solution_3.5.sln"). The projects that are using .NET 2.0 will build both in VS2005 and Orcas.

Personally, I will probably use the magnificent "/upgrade" command-line switch to convert all solutions while keeping in mind that I have an option to tweak the files by hand (sometimes it may come in handy if you need to quickly rollback certain solution to VS2005).

And another conclusion - reading blogs can be very useful and save lots of time :)