A few days ago I got a email form Eric Wells that got my attention and I want to describe in more detail. In his mail he asked me the following:
I have read several places that you can have an e-mail sent to a specific person (Project Manager) if someone overrides a check in policy. I was wondering if you know how to specify the e-mail address this report is sent to?
Eric is right. In all the talks I give myself I state that someone can receive a message that a policy override took place. It’s always funny to mention that your project lead get’s mail notifications if you are not obeying the rules. But Eric is also right that there is never discussed how this is done.
After the question I felt the urge to give everyone more insight on how this can be achieved. One thing to note here is that in the visual studio IDE there is no place where you can register for this event. After some digging around I found that the only way to achieve this is to create a little program myself to fix the problem of creating a subscription for this event.
So, What do we need to do?
We need to get in touch with the event system of team foundation server and register a subscription to an event within the system. The event system enables you to make a subscription for all available events in the team foundation server. The great thing about the event system is that we can specify how we would like to get the event delivered. We can choose for: Email, Plain text or Soap. So you can get mail but also an invocation of a specific web service you register. This enables you to take programmatic actions based on events fired by team system. Especially great is that the implementation also has a guaranteed delivery system using SQL server.
[Update, as Buck hodges points out in his comment, Team System does use SQL server but does not have guarenteed delivery as I point out here. The events are not recorded in a transaction with the work that generates the event. So the delivery of events is very robust but not guaranteed. Thanks Buck, for pointing that out.]
In the default setup of team foundation server the following events are available for subscription. (The events marked red are the one available to the end user in the VS.NET IDE.)
- Build Completion Event
- Build Status Changed Event
- BranchMovedEvent
- NodeCreatedEvent
- NodePropertiesChangedEvent
- NodeRenamedEvent
- NodesDeletedEvent
- ProjectCreatedEvent
- ProjectDeletedEvent
- CheckinEvent
- WorkItemChanged
We need to take a subscription to a checkinEvent but only have this fired at a special occasion when a policy violation has been overruled. The event system has the option to specify a filter on when the event fires. A filter can be constructed in a filter language called VSEFL (Visual Studio Event Filter Language). The expression syntax is modeled after SQL expressions, with some additional operations. We need to construct a filter that ensures the event only fires when a set of fields in the checkinEvent match the filter criteria. But the big question is what fields are available for the checkinEvent?
The answer to this can be retrieved from the Team System Database. Here you find the table tbl_event_type. The column event_type_schema contains the schema for the event and states the following set of available fields:
- Title
- ContentTitle
- Owner
- Committer
- Number
- CreationDate
- Comment
- TimeZone
- TimeZoneOffset
- TeamProject
- PolicyOverrideComment
- Notice
- Subscriber
- CheckinNotes
- PolicyFailures
- CheckinInformation
- Artifacts
Note: not for all events the schema can be found in this column. If you go to the Team System installation folder you can find a set of schema’s as well for some additional events that are available.
To create the correct filter we use the PolicyOverrideComment field that must be <> ‘’ and we are only interested in a specific project so we use the TeamProject field as well. So the filter expression should be: TeamProject = ‘MyProjectName’ AND PolicyOverrideComment <> ‘’
Now we need to define the subscription in the server. Therefore we can use the object model that is provided to us. You can find the required assemblies for the code I will show below in the folder: c:program filesMicrosoft visual Studio 8common7ideprivateAssemblies
You need to connect to the team foundation server, get a reference to the eventservice and use the SubscribetoEvent method to create the subscription. You get a subscriptionId back that you can use to unsubscribe to the event.
Below I have the full code sample for a forms application that provides you a convenient interface to create a subscription for the project you want. I wilt try to make the full code available in a downloadable and direct working format, but I need to find some web storage to make this work. (our blog engine does not have this kind of ability yet) [Download the zip file with source code here]
I hope you find this a useful addition that takes away the feeling that this is only possible in theory. With this very simple piece of code you van make this really work.
[Edit: This code is based on RC1 of Team Foundation Client running against Beta 3 of Team foundation Server]
—– Sample code —–
namespace SubScribeToPolicyViolation
{
public partial class Form1 : Form
{
TeamFoundationServer server = null;
public Form1()
{
InitializeComponent();
}
private void btnSubscribe_Click(object sender, EventArgs e)
{
// check if all fields are valid
if ((txtUserName.Text.Length > 0) &&
(txtDomain.Text.Length > 0) &&
(comboBox1.SelectedItem.ToString().Length > 0))
{
IEventService eventEndpoint =
(IEventService)server.GetService(typeof(IEventService));
DeliveryPreference delPrev = new DeliveryPreference();
delPrev.Type = DeliveryType.EmailHtml;
delPrev.Schedule = DeliverySchedule.Immediate;
delPrev.Address = txtEmail.Text;
string userId = txtDomain.Text + @”” + txtUserName.Text;
eventEndpoint.SubscribeEvent(userId, “CheckinEvent”,
“TeamProject = ‘” + comboBox1.SelectedItem +
“‘ AND PolicyOverrideComment <> ” “, delPrev);
}
else
{
MessageBox.Show(“Please Fill in all required fields”);
}
}
private void btnConnect_Click(object sender, EventArgs e)
{
server = TeamFoundationServerFactory.GetServer(textBox1.Text);
server.Authenticate();
ICommonStructureService structureService =
(ICommonStructureService)server.GetService(
typeof(ICommonStructureService));
ProjectInfo[] projects = structureService.ListAllProjects();
comboBox1.Items.Clear();
foreach (ProjectInfo project in projects)
{
comboBox1.Items.Add(project.Name);
}
groupBox1.Enabled = true;
}
}
}
3 comments
I’m using the RTM version and the SubscribeEvent completely ignores any userid(i.e. "DomainName\userName") I pass in. It always logs the subscription under the windows Identity I’m logged in under. Am I doing something wrong here?
davez
where to find subcription ID,.. to unsubscribe from email alerts
eventEndpoint.UnsubscribeEvent(?);
Murali
If you want to unsubscribe to the event you need to capture the returned EventID you get back calling the method event Endpoint.SubscribeEvent(…).
Code would then be something like:int eventId = Endpoint.SubscribeEvent(…).
Now you can use eventId to unsubscribe later.
marcelv