- GetFileName
- GetExtension
- GetFolderDepth
- Combine
- GetFolderName
- ValidatePath
Very useful.
toolsmith is the software equivalent of a tool-and-die specialist; one who specialises in making the tools with which other programmers create applications. [Jargon File]
Very useful.
I recently got this error while trying to create a branch from that its parent was renamed.
Here's an example of what happened:
I thought that the rename operation has broken the branch history. Looking at the branch dialog I saw that the source branch text box is read only and I thought to myself what would have happen if I had changed the source from $/Project/Folder2/Branch1 to $/Project/Folder1/Branch1. It was time for some coding…
private void PerformBranch(string server, string workspaceName, string userName, string changesetId, string sourceBranch, string targetBranch)
{
TeamFoundationServer tfs = new TeamFoundationServer(server);
VersionControlServer vcs = tfs.GetService(typeof(VersionControlServer)) as VersionControlServer;
Workspace workspace = vcs.GetWorkspace(server, userName);
VersionSpec versionSpec = VersionSpec.ParseSingleSpec(changesetId, userName);
workspace.PendBranch(sourceBranch, targetBranch, versionSpec);
}
This method has fixed the problem and after running it with the old branch path (source = $/Project/Folder1/Branch1), pending changes were waiting for check in.
So, how can you fix it?
There are 2 ways to do it:
Here's a code sample on how to update work item field values:
public void UpdateWorkItem(string serverUri, int id, string fieldName, string fieldValue)
{
TeamFoundationServer tfs = new TeamFoundationServer(serverUri);
tfs.EnsureAuthenticated();
WorkItemStore wis = tfs.GetService(typeof(WorkItemStore)) as WorkItemStore;
WorkItem workItem = wis.GetWorkItem(id);
workItem.Open();
workItem.Fields[fieldName].Value = fieldValue;
workItem.Save();
}
I was asked once by a friend if there's a way to filter the allowed values of a field when another field value changes. Well, the solution is not exactly as we think about filtering but more like a switch/case mechanism.
Let's take for example 2 fields that implement OS Platform & Version selection:
Windows --> XP, 2003 Server, Vista
Linux --> Ubuntu, Red Hat, Suse
Mac --> OS X 10.0, OS X 10.5
To implement this in the work item type definition file we need to define 2 fields. The xml should look like this:
<FIELD
type="String"
name="OS Platform"
refname="MyFields.OSPlatform">
<ALLOWEDVALUES>
<LISTITEM
value="Windows" />
<LISTITEM
value="Linux" />
<LISTITEM
value="Mac" />
</ALLOWEDVALUES>
</FIELD>
<FIELD
type="String"
name="OS Version"
refname="MyFields.OSVersion">
<WHEN
field="MyFields.OSPlatform"
value="Windows">
<ALLOWEDVALUES>
<LISTITEM
value="XP" />
<LISTITEM
value="2003 Server" />
<LISTITEM
value="Vista" />
</ALLOWEDVALUES>
</WHEN>
<WHEN
field="MyFields.OSPlatform"
value="Linux">
<ALLOWEDVALUES>
<LISTITEM
value="Ubuntu" />
<LISTITEM
value="Red Hat" />
<LISTITEM
value="Suse" />
</ALLOWEDVALUES>
</WHEN>
<WHEN
field="MyFields.OSPlatform"
value="Mac">
<ALLOWEDVALUES>
<LISTITEM
value="OS X 10.0" />
<LISTITEM
value="OS X 10.5" />
</ALLOWEDVALUES>
</WHEN>
</FIELD>
The version field contains WHEN rule for each platform. The result is a field that changes in real time when the parent field value changes.
You don't have to write the xml in order to achieve this. You can use the "Process Template Editor" which is part of the Team Foundation Server power tools to easily add fields and rules to you work item.
When installing windows with default language not set to english and changing it after installation you will notice that on the login screen the language is set to the language selected during installation. To change it english you need to edit the registry key HKEY_USERS\.DEFAULT\Keyboard Layout\Preload. In this key you will find probably 2 values named 1 and 2. You need to switch between the values so that the value named 1 will be set to 00000409 which is english. It happens to me when I get a new computer that is from a specific vendor and the OS is already installed.
I have installed Team Foundation Server 2008 Beta 2 on my staging environment this week. The installation process was smooth and except for some small issues I could start testing the release after a simple installation process.
Naturally, the first thing I have checked was the Team Build new features. I will not expand in the words regarding the new features because there are already some posts describing it (http://blogs.msdn.com/buckh/archive/2007/08/14/tfs-2008-a-basic-guide-to-team-build-2008.aspx). Anyway, some of the new features ease the management of the builds from the UI (Delete, Open Drop Folder…) and were available in Team Foundation Server 2005 using 3rdParty tools (TFSBuildManager). What I like the most is the Drop Management feature that completes the Continuous Integration feature. By using the retention policy of a build definition (Build Type is now Build Definition) you can define what and how to save builds. Builds can also be marked as save forever which can be useful when you want to mark a build that was released to a customer.
The second thing that I have checked was the new Team Build object model in this version. Since I'm a heavy consumer of the Team Build API I was curious to find out how it looks. For the record, TFSBuildManager works on Team Foundation Server 2008 (some of the interfaces became obsolete so I would probably have to work on a new version).
The first thing I have noticed is that the BuildStore interface became obsolete and it is replaced with the IBuildServer interface. So, in order to create an instance of the interface we need to do the following:
TeamFoundationServer tfs = new TeamFoundationServer("ServerName");
tfs.EnsureAuthenticated();
IBuildServer bs = (IBuildServer)tfs.GetService(typeof(IBuildServer));
In Team Foundation Server 2005 there was no interface to manage Build Type. If you wanted to query the server build types you needed to use the Version Control API to get the list of branches under the $/ProjectName/TeamBuildTypes branch. In 2008 the term Build Type is replaced with Build Definition. There is also a new interface to manage it named IBuildDefinition. Here's an example of how to get the list of build definitions for a project:
IBuildDefinition[] buildDefinitions = bs.QueryBuildDefinitions("ProjectName");
Another interface that became obsolete is the BuildData interface. Instead of using this interface we now have a new one named IBuildDetail. The following example shows the replacement for the method GetListOfBuilds that was available in 2005:
IBuildDetail[] buildDetails = bs.QueryBuilds("ProjectName");
The IBuildDetail interface is wider than the BuildData interface and it's in parallel to the big changes made to Team Build in 2008. Some of the new members we can use are:
One of the big changes in Team Build 2008 is the build agents. In 2005 build machines were related to a specific build type. In 2008, with the builds queue feature, you don't have to relate a build server to a specific build definition. Build servers are now treated as agents and can serve all build definitions. For each Build Definition you specify a default build agent. The build agent is represented through the IBuildAgent interface that was already available in 2005 but only for executing a build.
To get the list of build agents we need to do the following:
IBuildAgent[] buildAgents = bs. QueryBuildAgents("ProjectName");
To create a new build agent:
IBuildAgent buildAgent = bs. CreateBuildAgent("ProjectName");
buildAgent.MachineName = "BuildMachineName";
buildAgent.Name = "BuildAgentName";
buildAgent.BuildDirectory = @"C:\BuildDirectory";
buildAgent.Port = 9191;
buildAgent.Save();
There are some more properties to set for creating a new build agent but these are the required ones.
Starting a build is a little different too. Since we do not start a build but queue a build we need to use the QueueBuild method in the IBuildServer interface.
IBuildDefinition buildDefinition = bs. GetBuildDefinition("ProjectName", "BuildDefinitionName");
bs.QueueBuild(buildDefinition);
One thing I found missing in the current release API was the ability to edit build definition using the IProjectFile interface. The IProjectFile interface wraps the MSBuild project file but it is only available when creating a new build definition.
There is a lot more in the new Team Build API. I have tried to cover the basics in this post.
I hope I'll have some time soon to write the support for Team Build 2008 in TFSBuildManager. I already got some cool ideas using the new API.
Another problem I encountered was related to the databases restore. I must say that it was my mistake since I did not follow the process and restored the databases by detaching the new ones and attaching the old ones. The issue was that the 2 databases using full text search catalog (TfsWorkItemTracking and STS_Content_TFS) were attached with the wrong reference to the full text catalog. As a result the catalog could not be rebuilt and backups failed. In addition while searching work items using the Steps to Reproduce field (which is indexed in the catalog) an error raised specifing the query failed and there is a problem on the server.
I did some search using the errors I saw in the event viewer and in database logs and understood that the catalog needs to be rebuilt. When executing the rebuild using the management studio I got no error but the process ran for about 24 hours. I'm not a DBA but this seemed strange so I stopped it and continue searching using this keywords: "Full-Text Search is not enabled for the current database", "Property FullTextIndexSize is not available for FullTextCatalog" and with the names of the catalogs: ix_STS_Content_TFS and TeamFoundationServer10FullTextCatalog. I did not find much (except for this incomplete posts). Anyway, I understood that I have to drop and recreate the catalogs. After doing this the catalogs were rebuild and everything worked.
Here are the steps I took to recreate the catalogs.
Please notice that this part is done by the Team Foundation Server installation and I did this only because the catalogs were corrupted. If you are not familiar with this stuff I suggest you consult with a Team System advisor or try to reinstall the server. Any way don't forget to backup the database. Since in this case you have problem doing it because the corrupted catalogs disturb the backup I suggest you copy the data files (mdf and logs) to another location (after you stop the system...) or find a way to disable backing up the catalogs (I read about it some where).
Open Microsoft SQL Server Management Studio and connect to the Team Foundation Server database.
For recreating the ix_STS_Content_TFS catalog do the following:
For recreating the TeamFoundationServer10FullTextCatalog catalog do the following:
That's it. The catalogs were created and you should be able to process them.
The previous post in this series was about the build steps section of the build report. In this post we will see how to retrieve the associated changesets section details.
Using the BuildStore object we have created in this post we can get a list of ChangeSetData objects that contain the needed information (an example on how to get the buildUri parameter value available in this post also):
ChangeSetData[] changesets = buildStore.GetChangeSetsForBuild(buildUri);
foreach (ChangeSetData changeset in buildReport.Changesets)
{
MessageBox.Show(changeset.ChangeSetId.ToString());
MessageBox.Show(changeset.ChangeSetUri);
MessageBox.Show(changeset.CheckedInBy);
MessageBox.Show(changeset.Comment);
}
In this example I will show how to use the WorkItemStore interface. This example will execute a stored query on the work items database and will extract the attachments from the work items returned from the query. This is a good training for working with the WorkItemStore interface.
private void ExtractWorkItemsAttachments(string teamFoundationServer, string teamProject, string storedQuery,
string saveTo)
{
//Logon to the server and create the needed objects
TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(teamFoundationServer);
tfs.EnsureAuthenticated();
WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
Project tfsProject = store.Projects[teamProject];
StoredQueryCollection sqc = tfsProject.StoredQueries;
string querystring;
//Search for the query
foreach (StoredQuery query in sqc)
{
if (query.Name == storedQuery)
{
//Execute the query
querystring = query.QueryText;
querystring = querystring.Replace("@project", "'" + tfsProject.Name + "'");
WorkItemCollection workItems = store.Query(querystring);
//Extract the attachments
foreach (WorkItem workItem in workItems)
{
if (workItem.Attachments.Count > 0)
{
foreach (Attachment attachment in workItem.Attachments)
{
//Using WebClient to download the attachment
WebClient webClient = new WebClient();
webClient.Credentials = CredentialCache.DefaultCredentials;
string fileName = Path.Combine(saveTo, attachment.Name);
webClient.DownloadFile(attachment.Uri.AbsoluteUri, fileName);
}
}
}
}
}
}
I have notice that there is a lot of traffic to my Blog because of a post I have about exporting Excel chart to an image. I thought that it would be good to share more stuff about Excel automation in C#. Below you can find a method to export data into excel sheet. This function uses a list view as the data source.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Threading;
using System.Drawing;
using ExcelAutomation = Microsoft.Office.Interop.Excel;
namespace ExcelUtils
{
public static class Excel
{
private static void BorderAroundCell(ExcelAutomation.Range CellRange)
{
CellRange.BorderAround(ExcelAutomation.XlLineStyle.xlContinuous,
ExcelAutomation.XlBorderWeight.xlThin,
ExcelAutomation.XlColorIndex.xlColorIndexAutomatic,
Type.Missing);
}
public static void ReportFromListView(string reportName, ListView
listView)
{
ExcelAutomation.Application excelApp = new ExcelAutomation.ApplicationClass();
excelApp.UserControl = true;
CultureInfo oldCultureInfo = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
ExcelAutomation.Workbook workbook = excelApp.Workbooks.Add(Type.Missing);
ExcelAutomation.Worksheet worksheet = (ExcelAutomation.Worksheet)workbook.Worksheets.get_Item(1);
worksheet.Name = reportName;
//Headers
foreach (ColumnHeader columnHeader in listView.Columns)
{
worksheet.Cells[1, columnHeader.Index + 1] = columnHeader.Text;
}
string[] letters = new string[26]{"A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
for (int i = 0; i < listView.Columns.Count; i++)
{
string headerCell = letters.GetValue(i) + "1";
worksheet.get_Range(headerCell, headerCell).Font.Bold = true;
BorderAroundCell(worksheet.get_Range(headerCell, headerCell));
worksheet.get_Range(headerCell, headerCell).Interior.ColorIndex = 36;
}
//Content
for (int i = 0; i < listView.Items.Count; i++)
{
for (int j = 0; j < listView.Columns.Count; j++)
{
string dataCell = letters.GetValue(j) + (i + 2).ToString();
worksheet.Cells[i + 2, j + 1] = listView.Items[i].SubItems[j].Text;
BorderAroundCell(worksheet.get_Range(dataCell, dataCell));
}
}
worksheet.Columns.AutoFit();
worksheet.Columns.HorizontalAlignment = ExcelAutomation.XlHAlign.xlHAlignLeft;
excelApp.Visible = true;
Thread.CurrentThread.CurrentCulture = oldCultureInfo;
}
}
}
We have published a new Terminals version (1.0 Prodcution). You can download it at here.
Here are the available changes for this release:
1. Support for RDP 6:
2. Save position and size.
3. Nicer about box...
4. Execute before connect (per connection and for all connections).
5. Some additional bugs were fixed.
Enjoy.
To be continued.
I wrote it because I needed the ability to manage build types outside Visual Studio environment. Also, I needed some features that are not available through Visual Studio IDE.
I'm planning to add:
Enjoy.