Showing posts with label Team Foundation Server. Show all posts
Showing posts with label Team Foundation Server. Show all posts

Wednesday, June 9, 2010

VS2008 to VS2010 Upgrade Notes

UPDATE 6/23/2010:

The issue with one of our setup project builds has been successfully resolved with a workaround that I thought didn’t work at first.  It turns out our Microsoft contact couldn’t reproduce the issue.  It was the end of the day so I decided to shelve this issue until this morning.  I tried running the setup project from my XP machine with the workaround and it worked.  More importantly, I ran it on our build machine and it worked!  The thing that threw me off was that it failed on my Windows 7 development machine, which is where I initially tested the issue.  I suspect it might have to do with the fact that the interop assemblies were actually built on my old XP development environment and that something isn’t jiving now when I use the same assemblies to build on my Windows 7 machine.  In any case, copying the interop dlls to the same path as the vdproj file works like a charm.

 

 

Using the latest and greatest development environment is always fun.  However, upgrading from a previous version isn’t always easy.  When we converted our dev environment from VS2005 to VS2008, there were a number of headaches to get everything working properly.  So far, upgrading to VS2010 from VS2008 is proving no different.  Since we’re still on TFS2008, we used this workaround to build VS2010 solutions on our Build machines. 

So after our build machines had VS2010 installed and the above MSBuildPath workaround was applied, I ran my first build.  It was a ClickOnce build and it actually ran without any issues.  The application compiled and everything got copied over to our drop location…Cool!  So then I tried running our MSI build for the same project.  I was expecting it to build fine since the ClickOnce build is a little bit more complex, but the MSI build failed.  After thoroughly checking all settings in the Setup project, I couldn’t figure out why it was failing.  The only reason in the BuildLog.txt was EXEC : error : Unable to update the dependencies of the project.  Could the message be a bit more vague, please?

After searching the web, it seemed others were having the same problem.  The workarounds suggested on that page didn’t work for us.  So instead of waiting around, we decided to open up a support ticket, which our contact at Microsoft is currently looking into.  I had a feeling that Interop assemblies in our project might be causing the problem, but it wasn’t until today that my suspicion was gaining ground.  We have a few projects that have MSI builds, so I went ahead and converted and built those out.  What do you know?  The MSI builds that don’t have Interop assemblies build fine on our build machine.  We’re still waiting for a real solution to this problem, until then, we’re building the MSI package locally for that one project.

Another one of our builds has unit tests.  I ran this project’s build without the unit tests first and it completed.  I then ran the build with the unit tests and 99.9% of the unit tests failed, but not all of them, which was weird to me.  These unit tests passed completely when we were using VS2008, so maybe the MSTest reference needed to be updated or something.  I searched MSDN and found this post about the same exact issue we were having.  I tried the solutions suggested, but they didn’t work.  There were some other odd issues with the build with the unit tests, so I just decided to delete the workspace associated with that build.  After I did this, the unit tests passed and everything looked good.

I hope when we upgrade our TFS2008 to TFS2010, that there aren’t going to be more issues.  I have my fingers crossed…

Wednesday, November 18, 2009

TFS folders and the evil “&”

So I tried to make a folder within TFS called “R&D and it let me.  No surprises…yet.  After moving a project into this folder, I ran the project to make sure all paths/references were still intact.  The project ran fine so things seemed okay. 

It wasn’t until I tried opening a form up in Designer view that I got a weird error:

DesignerError

How is it that the project can build and run fine, but I’m seeing this?  XML?  I don’t have anything related to XML in the form code, so what gives?  After doing some searching on the internet, it seems that the “&” character anywhere in the path causes this issue.  Since my project was in the “R&D” folder, I was having this issue.  I renamed the folder and the problem went away…

Thursday, June 19, 2008

TeamBuild ClickOnce – Auto Incrementing Your Version Information

Using AssemblyInfoTask within your TFSBuild.proj file, you can set your builds to automatically increment your AssemblyVersion and AssemblyFileVersion.  You can also keep your application’s Publish Version in sync, which is useful if you’re publishing your application via ClickOnce. 

The Publish Version is important because that’s what ClickOnce looks at to see if there’s a new version available when the user runs the application.  Updating the AssemblyVersion or AssemblyFileVersion doesn’t tell ClickOnce that there’s a new version of your application to download.

There are a ton of blog posts like this one that tell you how to check in/out files from your TFS so I won’t repeat those steps.  The actual version updates happen inside the <AssemblyInfo> task:

<Project>
    <Import Project="$(MSBuildExtensionsPath)\Microsoft\AssemblyInfoTask\Microsoft.VersionNumber.Targets" />
    ...
    <Target Name="AfterGet">
        <Message Text="In After Get"/>

        <CreateItem Include="$(SolutionRoot)\My Project\AssemblyInfo.vb">
            <Output ItemName="AssemblyInfoFiles" TaskParameter="Include"/>
        </CreateItem>

        <Exec WorkingDirectory="$(SolutionRoot)\My Project\"
            Command="$(TF) checkout AssemblyInfo.vb" />

        <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFiles)"
            AssemblyRevisionType="AutoIncrement"
            AssemblyRevisionFormat="0"
            AssemblyFileRevisionType="AutoIncrement"
            AssemblyFileRevisionFormat="0">

          <Output ItemName="MaxAssemblyVersion" TaskParameter="MaxAssemblyVersion" />
        </AssemblyInfo>
      </Target>
    ...
</Project>

For our project, we only want to update a specific AssemblyInfo.vb as opposed to recursively checking out all AssemblyInfo files to modify.  We used the <CreateItem> task to store the AssemblyInfo files into an array.  In our case it’s just one file (That’s why the <Exec> task looks a bit different than most examples out there on the web). 

Inside the <AssemblyInfo> task is pretty self-explanitory.  Setting the type and format of the Revision (you can do this to your Major, Minor, and Build as well) to AutoIncrement is what does the trick.  You don’t have to have an <Output> element, but I wanted to keep our Publish Version and Assembly Version in sync. 

We can use the variable @(MaxAssemblyVersion), which stems from the ItemName attribute, to hold our new Assembly Version.  I’ve previously posted about modifying the vbproj file to update the Publish Version so I won’t go into the details, but finding and replacing the needed element isn’t difficult.  Lastly you’ll want to check in your new AssemblyInfo file so that the next build increments your versions. 

Tuesday, June 3, 2008

TeamBuild ClickOnce – Publishing To Different Locations

Our team's goal with TeamBuild is to keep things as automated as possible.  We currently have two separate publishing locations for production and beta releases.  Wouldn't it be nice if we didn't have to put the publishing location manually each time we put out a build?

publish

What I found interesting inside my project's vbproj file (which is just XML) was that the information I needed was located within the <PublishUrl> element:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
  <PropertyGroup>
    ...
    <PublishUrl>http://somelocation/</PublishUrl>
    ...
  </PropertyGroup>
</Project>

Great, we can now have two different build definitions for production and beta releases without having to manually enter the publishing location.  All we need to do is write the location in the vbproj file before we compile.  The problem is that TFS has the vbproj file (and I’m pretty sure all other files within your project) as read-only during a build.

My first thought was that I just needed to checkout the vbproj file, do my modification, then just check it in.  This worked fine, but was all that really necessary?  I thought of using attrib.exe to remove the read-only attribute from the file, but I didn’t know if it’d work because of the TFS source control files.  I got confirmation from a post that attrib.exe would do the job so that’s what I ended up doing in my TFSBuild.proj:

<Project ...>
    ...
    <Target Name ="BeforeCompile">
        <Message Text="In Before Compile"/>

        <Message Text="Making vbproj file writable"/>
        <Exec Command="attrib -R &quot;$(SolutionRoot)\project.vbproj&quot;"/>
        ...
    </Target>
    ...
</Project>

Now we just have to modify the <PublishUrl> element with our publishing location.  If you’ve read my previous posts you know that we use the SDC Tasks Library for XML manipulation.  So the first stab I took at placing our publishing locations into the vbproj file was using the <XmlFile.SetValue> task.  The problem here is that the default namespace in the vbproj file isn’t prefixed so getting the XPath I needed didn’t work.  The solution was to use the <File.RegEx> task:

<Project ...>
    ...
    <Target Name ="BeforeCompile">
       <Message Text="In Before Compile"/>

       <Message Text="Making vbproj file writable"/>
       <Exec Command="attrib -R &quot;$(SolutionRoot)\project.vbproj&quot;"/>

       <Message Text="Replacing PublishUrl"/>
       <File.RegEx
         Path="$(SolutionRoot)\project.vbproj"
         RegularExpression="&lt;PublishUrl&gt;(.*?)&lt;/PublishUrl&gt;"
         NewValue="&lt;PublishUrl&gt;http://YourSpecifiedLocation/&lt;/PublishUrl&gt;"
       />
    </Target>
    ...
</Project>

When the project compiles, it’ll use the updated vbproj’s information so the manifests will have the correct publishing information when built.  Using this method, you can still manually publish your ClickOnce without messing up your build definitions and also have various build definitions to specify different publishing locations. 

One thing to note is that the Publish Version in the IDE is the <ApplicationVersion> element in your vbproj file.  If you modify this in your IDE then this will also affect your builds.  I found that keeping your Assembly Version and Publish Version in sync the best way to do things.  This way nobody gets confused as to which version you might be talking about.  Also, ClickOnce checks your Publish Version when doing automatic updates so keep that in mind.

Monday, May 19, 2008

TeamBuild ClickOnce – Versioning

It seems many people have had issues getting the version number correctly within their tfsbuild.proj files to use in their ClickOnce html files.  The solutions I've seen were very complicated, but this may be because the examples I've seen were in TFS 2005 or they were using different tasks.

My coworker added the SDC tasks to our build server because there is functionality for XML and file manipulation.  From his starting point I went on to look further into two specific tasks: Xml.GetValue and File.RegEx.

My boss directed me to where I can find the version number that I needed, which resides in the application manifest file.  The trickiest part of the Xml.GetValue task to me was understanding XPath.  The biggest point that I missed was that I needed to define the namespace within the application manifest to get to the element. 

If you look inside the application manifest of your program (not the program.exe.manifest, but program.application as I'm dealing with publishing), you'll find something similar to this:

<?xml version="1.0" encoding="utf-8"?>
    <asmv1:assembly 
        xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" 
        manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" 
        xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" 
        xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" 
        xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" 
        xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  
    <assemblyIdentity name="program.application" version="1.0" 
        publicKeyToken="abcdedf892929" language="neutral" processorArchitecture="x86" 
        xmlns="urn:schemas-microsoft-com:asm.v1" />
...
</asmv1>

I thought I could just use an XPath like this /asmv1:assembly/assemblyIdentity/@version to get the value that I wanted.  Nope, my build threw errors saying that the namespace asmv1 was not defined.  Then I defined the asmv1 namespace, but I wasn't getting a value returned.   You'll notice in the snippet above that assemblyIdentity adds its own namespace, but it's same as asmv1 defined above.  In the end it was because I didn't prefix the asmv1 namespace before assemblyIdentity as well.

I manually published my project to get the publish.htm file.  I then made it a part of my project so that I could copy it to my published application's directory and modify the version number.  I edited the html file and put a #VERSION# tag so that the File.RegEx task could find it and replace it with the $(ResultsItem) variable.  We get $(ResultsItem) from the ItemName attribute of the Output element within the Xml.GetValue task element.  The following is the snippet of my tfsbuild.proj file that does the versioning of the publish.htm file:

<Project>
...
    <Target Name="AfterCompile">
        <Copy SourceFiles="$(SolutionRoot)\SupportFiles\publish.htm" DestinationFolder="$(OutDir)" />
    </Target>

    <Target Name="AfterDropBuild">
        <Message Text="Extracting version from Application manifest..."/>

        <Xml.GetValue
            NameSpaces="asmv1=urn:schemas-microsoft-com:asm.v1"
            Path="$(DropLocation)\$(BuildNumber)\x86\Release\program.application"
            XPath="/asmv1:assembly/asmv1:assemblyIdentity/@version">
      
            <Output TaskParameter="Results" ItemName="ResultsItem"/>
        </Xml.GetValue>

        <Message Text="Updating publish.htm to version @(ResultsItem)"/>
    
        <File.RegEx
            Path="$(DropLocation)\$(BuildNumber)\x86\Release\publish.htm"
            RegularExpression="#VERSION#"
            NewValue="@(ResultsItem)" />
    </Target>
...
</Project>
 

Friday, May 16, 2008

TeamBuild ClickOnce – Automation

I've had a ton of issues trying to get ClickOnce to work with MS Team Build starting from TFS 2005; we're now using TFS 2008.  Getting a bootstrap package to work with TeamBuild took some work, but I was able to do it with success early on. 

In our 2005 environment, I had to place the signing certificate that I was using onto our build server and place it in the certificate store in order for any of my builds to work.  Without the stored certificate my builds would not complete.  Fine, my bootstrap packages work, but my ClickOnce builds didn't.  I didn't feel too bad because a ton of people out there have had issues with ClickOnce and Team Build. 

Fast forward to our 2008 environment.  I had some minor issues with my bootstrap package as I posted about when I started my blog, but nothing compared to the ClickOnce issues I've had.  I decided to create a new build for my project in VS 2008 and start fresh.  I still got the same result: my build would hang and return no warnings. 

My coworker got ClickOnce automation working on his project and I happy someone finally got it to work.  I really couldn't find any difference in our processes as far as the build automation went.  My project has a lot more dependencies, but that didn't seem to be the cause of my problems. 

Every time I published my application manually, the certificate asked for a password.  This was the same password that I used to store the certificate on our build server.  My coworker's publishing didn't require him to enter one.  So then I thought to myself, maybe a password dialog is just sitting there waiting for input. 

The reason I came to this conclusion was that I did some testing and looked at the output directory of where my files were being published.  Everything was being created and copied except my ".application" file.  That triggered the thought that my certificate wasn't signing the application manifest because of a certificate password window just sitting there waiting for input.  The build process can't handle window pop ups.

My solution was to just create a new signing certificate with no password and this time I didn't place it in our build server's certificate store.  After adding the certificate to my project I ran my ClickOnce build and it worked...FINALLY! 

Thursday, May 15, 2008

MS Team Build Bug

Today while scouring the MSDN forums I found something interesting.  If you choose "Any CPU" as your platform in your "TFSBuild.proj" file, solution files will build correctly:

...
<ItemGroup>

    <SolutionToBuild Include="$(BuildProjectFolderPath)/../../project.sln">
        <Targets>Publish</Targets>
        <Properties></Properties>
    </SolutionToBuild>

</ItemGroup>

<ItemGroup>
 
 <ConfigurationToBuild Include="Release|Any CPU">
     <FlavorToBuild>Release</FlavorToBuild>
     <PlatformToBuild>Any CPU</PlatformToBuild>
 </ConfigurationToBuild>

</ItemGroup>
...

The problem is that I tried to publish a solution and for some reason it didn't work.  Actually, the reason was that I had references in my solution to non-publishable projects.  So it made sense then to just publish the project within the solution.  When I replaced the solution file with my VB Project file in the "SolutionToBuild" element, I got errors saying that the location of my executable couldn't be found.  I followed the suggestions on MSDN and changed my platform to x86. After making the change I was able to build both solution and project files:

...
<ItemGroup>

    <SolutionToBuild Include="$(BuildProjectFolderPath)/../../project.vbproj">
        <Targets>Publish</Targets>
        <Properties></Properties>
    </SolutionToBuild>

</ItemGroup>

<ItemGroup>
 
 <ConfigurationToBuild Include="Release|x86">
     <FlavorToBuild>Release</FlavorToBuild>
     <PlatformToBuild>x86</PlatformToBuild>
 </ConfigurationToBuild>

</ItemGroup>
...

Tuesday, April 8, 2008

MS Team Foundation Server / Team Build (Part 2)

Creating a stand alone setup.exe/msi wasn't as easy for me as it should have been. Following Microsoft's suggestion of adding the .vdproj file to my "AfterCompile" target in my TFSBuild.proj file did not work; I got a compile error.

<Project>
...
<Target Name="AfterCompile"> 
    <Exec Command="&quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv&quot;&quot;$(SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\HelloWorldTestInstaller.vdproj /Build &quot;Debug|Any CPU&quot;"/> 
    <Copy SourceFiles="$(SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\Debug\HelloWorldTestInstaller.msi" DestinationFolder="$(OutDir)" /> 
<Copy SourceFiles="$(SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\Debug\setup.exe" 
DestinationFolder="$(OutDir)" /> 
</Target> 
</Project>
What I ended up doing was replacing the .vdproj file with the entire .sln file. Then I copied the setup.exe and .msi files out to the specified drop directory.
<Project>
...
<Target Name="AfterCompile">
    <Exec Command="del &quot;$(OutDir)*&quot; /q" />
    <Exec Command="&quot;C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv&quot; &quot;$(SolutionRoot)\Project.sln&quot; /Build &quot;Debug|Any CPU&quot;" />
    <Copy SourceFiles="$(SolutionRoot)\ProjectSetup.msi" DestinationFolder="$(OutDir)" />
    <Copy SourceFiles="$(SolutionRoot)\setup.exe" DestinationFolder="$(OutDir)" />
</Target>
</Project>

MS Team Foundation Server / Team Build (Part 1)

I've had to setup my current project at work so that it uses TFS's build automation. "F5 is not a compile solution" as I've been told by my boss. I completely agree with this because I've run into the whole "well it works on my machine" syndrome many times.

Having a dedicated server to compile my solution gives me a better grasp of how things would work on a machine that didn't have all of my development tools on it (aside from what's required by Team Build).

I also had the pleasure (more like pain) of upgrading my TFS 2005 build script to 2008 when we upgraded. This in itself is really simple to do, you just simply move it on over and TFS 2008 just runs the 2005 version in compatibility mode.

However, I didn't want to just run an older version so I just copied out the part that I wanted from the 2005 version, re-ran the wizard to build a 2008 version, and pasted the chunk of text. Much to my disappointment, the build script didn't work anymore.

I looked at my file over and over again. I and others on the MSDN forums found nothing wrong with it. Finally, it was suggested I just delete the TFSBuild.proj file on the build server so that TFS copies it to the build server again... it worked.

Lesson learned: be sure to check out the TFSBuild.proj file when making edits and don't modify in memory if that message box comes up. I spent a good part of a whole week trying to figure out why it wasn't working.