Showing posts with label Code Snippet. Show all posts
Showing posts with label Code Snippet. Show all posts

30 December 2008

Get Files Associated with a Build

One of the greatest features of Team Foundation Server is it's extensibility via the TFS Object Model.  A short while back I received a question asking how to retrieve a list of all files included in all the changesets associated with a build.  The intent (of the person asking the question) was to deploy only those files that had been modified in one of the changesets.

The following code example is what I came up with.  I can't say it's the only way, or even the most efficient way, to achieve the desired result, but it's at least one way :-)  I've also posted this example on TFSExamples.com, here.



/// <summary>
/// Gets a list of files included in all changesets associated with the specified build URI.
/// </summary>
/// <param name="tfServerName">The name of the Team Foundation Server server.</param>
/// <param name="buildUri">The URI of the build to retrieve items for.</param>
/// <param name="workspaceName">The name of the workspace that's used to map server items
/// to local items (e.g. to a file on the client machine).</param>
/// <param name="workspaceOwner">The workspace owner.</param>
/// <returns>A list of files included in all changesets associated with the specified
/// build URI.</returns>
/// <remarks>You can specifiy an empty/null <paramref name="workspaceName"/> and/or
/// <paramref name="workspaceOwner"/> if you want a list of server items returned.</remarks>
private List<string> GetFilesAssociatedWithBuild(string tfServerName, Uri buildUri, string workspaceName, string workspaceOwner)
{
var buildFiles = new List<string>();
Workspace workspace = null;

// Obtain cached instance of TeamFoundationServer (if a match is found). If the current credentials are not
// valid, then a connection dialog will be displayed when EnsureAuthenticated is called below
var tfServer = TeamFoundationServerFactory.GetServer(tfServerName, new UICredentialsProvider());

// Ensure the current user can authenticate with TFS
_teamFoundationServer.EnsureAuthenticated();

// Get a reference to the build service
var buildServer = (IBuildServer)tfServer.GetService(typeof(IBuildServer));

// Get a reference to the version control service
var versionControl = (VersionControlServer)tfServer.GetService(typeof(VersionControlServer));

// Get the workspace used to map server items to local items
if (!string.IsNullOrEmpty(workspaceName) && !string.IsNullOrEmpty(workspaceOwner))
{
workspace = versionControl.GetWorkspace(workspaceName, workspaceOwner);
}

// Get the build specified by the selected build URI
var build = buildServer.GetBuild(buildUri);
if (build != null)
{
// Get a list of all changesets associated with the selected build
var changesets = InformationNodeConverters.GetAssociatedChangesets(build);
if (changesets != null)
{
// Iterate through all changesets associated with the selected build
foreach (var changesetSummary in changesets)
{
// Get the changeset for the specified ID
var changeset = versionControl.GetChangeset(changesetSummary.ChangesetId);

if (changeset.Changes != null)
{
// Add each file associated with the current changeset
foreach (var changesetItem in changeset.Changes)
{
if (workspace != null)
{
// Since a workspace is available, map the server item to a local item
item = workspace.GetLocalItemForServerItem(changesetItem.Item.ServerItem);
}
else
{
// A workspace was not provided, so return the server item
item = changesetItem.Item.ServerItem;
}

// Do not add duplicate filenames
if (!buildFiles.Contains(item))
{
buildFiles.Add(item);
}
}
}
}
}
}
return buildFiles;
}





30 June 2008

Creating Team Build Types

I was answering a question related to programmatically creating team build types today and realized there weren’t too many examples on the web.  I didn’t see any examples that included all the details I was looking for – for example:

  • Adding the solution to be built to the new build type
  • Turning on/off test execution
  • Turning on/off code analysis

An example containing these details may exist, I just didn’t come across it during my initial search.

So, with that said, I decided to post the main part of the example application I put together to test out some concepts.  The items listed above are included in the example code below.

The example code includes two methods:

  • CreateBuildType – this method accepts six arguments that can be used to programmatically create a new build type.
  • VersionControlItemExists – this is a helper method that determines whether an item already exists in version control.

Although the example below can be used to create a new build type “as is”, there is always room for improvement.  For example:

  • Add a parameter to specify the default build agent.  Currently, the first build agent returned is used as the default when creating the build type.
  • Add a parameter to control the exact placement of the build type in version control (a common pattern is used in the example below).
  • Throw exceptions instead of displaying message boxes when exceptional conditions arise.  The message boxes were used for example purposes only.

With that said, here is the source code…

using System;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Common;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.VersionControl.Common;



private static bool CreateBuildType(string serverName, string teamProject, string buildName, string solutionPath, string dropFolder, bool runTests)
{
// Get a connection to Team Foundation Server
TeamFoundationServer tfServer = TeamFoundationServerFactory.GetServer(serverName, new UICredentialsProvider());

// Get a reference to a build service
IBuildServer buildServer = (IBuildServer)tfServer.GetService(typeof(IBuildServer));

// Get a list of build agents associated with the specified team project
IBuildAgent[] buildAgents = buildServer.QueryBuildAgents(teamProject);

if (buildAgents.Length == 0)
{
MessageBox.Show(
@"The specified Team Project does not have any build agents associated with it. Please create at least one build agent.",
"No Default Build Agent Found",
MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;
}

// Create the new build type definition
IBuildDefinition buildType = buildServer.CreateBuildDefinition(teamProject);

// Specify the name of the new build type
buildType.Name = buildName;

// Specify where the new build type should be stored in version control
buildType.ConfigurationFolderPath = string.Format(@"$/{0}/TeamBuildTypes/{1}", teamProject, buildName);

// Set the default build agent
buildType.DefaultBuildAgent = buildAgents[0];

// Set the default drop location
buildType.DefaultDropLocation = dropFolder;

if (!VersionControlItemExists(tfServer, buildType.ConfigurationFolderPath))
{
IProjectFile projectFile = buildType.CreateProjectFile();

// Add a new solution to be built to the project
ISolutionToBuild solution = projectFile.AddSolutionToBuild();

// Set the path of the solution to build
solution.SolutionPath = solutionPath;

// Specify whether tests should be ran or not
projectFile.RunTest = runTests;

// Run code analysis if the project is setup to do so
projectFile.RunCodeAnalysis =
CodeAnalysisRunType.Default;

// Save the project file
projectFile.Save(buildType.ConfigurationFolderPath);

// Save the new build type
buildType.Save();
}
else
{
// The specified build type already exists
MessageBox.Show(
"The specified Build Type already exists. Please specify a different Build Type name.",
"Build Type Already Exists",
MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;
}

return true;
}


private static bool VersionControlItemExists(TeamFoundationServer tfServer, string itemPath)
{
string projectFilePath = VersionControlPath.Combine(itemPath, BuildConstants.ProjectFileName);

return ((VersionControlServer)tfServer.GetService(typeof(VersionControlServer))).ServerItemExists(
projectFilePath, VersionSpec.Latest, DeletedState.NonDeleted, ItemType.File);
}

08 February 2008

MSDN Code Gallery

Although it's been about two weeks since Microsoft launched its new MSDN Code Gallery, I am just now getting around to checking it out.

At first glance, it appears there are quite a few similarities between the MSDN Code Gallery and Microsoft's CodePlex site (another open source site provided by Microsoft and hosted on top of Team Foundation Server).  So, what are the differences between the two sites?  Basically, it boils down to project management: Microsoft's CodePlex site is suited for open source projects requiring some level of project management whereas the MSDN Code Gallery is mainly an on-line repository of code snippets and example projects (without any of the project management functionality).

What I like:

  • The MSDN Code Gallery is a visually pleasing site.
  • Quick and simple site for accessing code snippets (without having to pull down entire projects to get at a small snippet).
  • "Tagged" resource pages allowing for simple categorization of code snippets and examples.
  • Creating a new resource page is relatively easy.

What I don't like:

  • Not a lot of content.  As of a few minutes ago, there were only 75 "resources" available for download on the site.  However, this is still a new site and I'm sure it will grow a lot over time.
  • Figuring out the navigation and search features takes a little getting used to.  It's nice once you figure it out but is not intuitively obvious.
  • You must have a Windows Live ID (formerly known as Microsoft Passport) to create new resource pages.  The CodePlex site does not have this "limitation" (possibly due to the integration issues with TFS).
  • The instructions for setting up the resource page (correctly) and publishing it are not clear.  I followed the instructions and published my first code snippet (for sending e-mail messages in C# or VB.NET) only to receive an e-mail message a few hours later telling me that my resource page "appeared" to still be in testing - which it wasn't.  I've sent an e-mail asking for specific details as to what the actual problem is so I can get that corrected.
  • The only license model available is the Microsoft Public License (Ms-PL).  This license is fairly permissive (no pun intended) but what does it hurt to have a few more choice (similar to the CodePlex site)?
  • The search functionality is fairly basic.  Having some extended search features such as language choice (e.g. C#, VB.NET, JavaScript, etc.), submission date, etc. would be beneficial.  The krugle search engine does a good job in this area (as an example).

I've always tried to make use of example source code snippets as I develop software just so I don't have to re-invent the wheel.  However, a lot of the source code resources on the web tend to have an abundance of poorly written/tested snippets or the snippets are out of date.  I will be interested in seeing how Microsoft deals with this issue over time (if at all).  Until then, I'll enjoy yet another snippet repository.

Follow Up: I received some more details about why my resource page "appeared" to still be in testing... Basically, I was told that my resource page needed to be "spruced" up with a little more information.  I must admit that my initial page was pretty sparse, but let's face it, a simple "send e-mail" snippet doesn't take a lot of explanation.  However, I can understand Microsoft's viewpoint that they do not want a lot of mostly-empty (or "ugly") pages comprising the MSDN Code Gallery.  So, I've updated the SendEmail resource page to hopefully meet the (not-so-well-documented) publishing requirements.

01 May 2007

Programmatically Download Attachments from TFS

I created this short snippet of code the other day in reference to a forum question on how to retrieve the linked items for a given work item.  The code below uses the TFS Object Model to retrieve a specific work item (in this case, item #16) and save all attachments to the local file system.

Code Snippet
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
using System.IO;

namespace DTTFSLib
{
public class WorkItemTest
{
public WorkItemTest(string serverName)
{
// Connect to the desired Team Foundation Server
TeamFoundationServer tfsServer = new TeamFoundationServer(serverName);

// Authenticate with the Team Foundation Server
tfsServer.Authenticate();

// Get a reference to a Work Item Store
WorkItemStore workItemStore = new WorkItemStore(tfsServer);

// Retrieve a Work Item by ID - in this case, bug #16
WorkItem workItem = workItemStore.GetWorkItem(16);

// Get attachments
if (workItem != null)
{
System.Net.
WebClient request = new System.Net.WebClient();

// NOTE: If you use custom credentials to authenticate with TFS then you would most likely
// want to use those same credentials here
request.Credentials = System.Net.CredentialCache.DefaultCredentials;

foreach (Attachment attachment in workItem.Attachments)
{
// Display the name & size of the attachment
Console.WriteLine("Attachment: '" + attachment.Name + "' (" + attachment.Length.ToString() + " bytes)");

// Save the attachment to a local file
request.DownloadFile(attachment.Uri, Path.Combine(@"C:\Attachments", attachment.Name));
}
}
}
}
}

 


Note that exception handling and custom authentication have been left out for brevity.


Check out the Essentials of Work Item Object Model MSDN site for more information on the work item object model.