Welcome to MSDN Blogs Sign in | Join | Help

Sample: Version Control RSS Feed

<%@ Page Language="c#" %>
<%@ OutputCache Duration="20" Location="Server" VaryByParam="state" VaryByCustom="minorversion" VaryByHeader="Accept-Language"%>

<%
// "Copyright © Microsoft Corporation.  All rights reserved.  These Samples are based in part on the Extensible Markup Language (XML) 1.0 (Third Edition) specification Copyright © 2004 W3C® (MIT, ERCIM, Keio. All rights reserved. http://www.w3.org/consortium/legal/2002/copyright-documents-20021231."
%>

<%
//This posting is provided "AS IS" with no warranties of any kind and confers no rights.  Use of samples included in this posting is subject to the terms specified at http://www.microsoft.com/info/cpyright.htm.
%>

<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Collections" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="Microsoft.TeamFoundation.Client" %>
<%@ Import Namespace="Microsoft.TeamFoundation.VersionControl.Client"%>
<%@ Import Namespace="Microsoft.TeamFoundation.VersionControl.Common" %>

<%
// Generate an RSS feed for Team Foundation Source Code Control checkins
//
// Note: Only one request per "pester interval" from each system will be honored. See
//       pesterInterval below.
//
// This feed returns information about the most recent N checkins. See maxCheckinCount
// below.
//
// Invoking this page without any parameters returns information about all Team
// Foundation checkins up to the maximum count. If a filename is supplied, information
// about the most recent checkins for that file only are returned. Specify a filename
// by adding ?serverPath=<serverPath>. Note that the filename must be expressed as a server
// pathname without the leading $/.
//
// E.g., to see the activity for a file $/teamProjectA/myFile, add this to the Url
// ?serverPath=teamProjectA/myfile
//
// This page returns no items if the file does not exist.

// ***************************************************
// (Default: off) Set this to true to throttle user requests by host/username
// ***************************************************
bool throttleRequests = false;

// Ignore requests from the same machine within this interval
int pesterInterval = 30 * 1000; // expressed in milliseconds

if (throttleRequests)
{
    // If the originating system has been serviced recently, drop the request
    object lastRequest = Context.Cache[User.Identity.Name+Request.UserHostAddress];
    if (lastRequest != null)
    {
        if ((int) lastRequest + pesterInterval < Environment.TickCount)
        {
            return;
        }
    }
}

// Default -- everything under $/
string serverPathname = VersionControlPath.RootFolder;

try
{
    // Check whether information on a specific file was requested
    string pathname = Request.Params["serverPath"];
    if (pathname != null)
    {
        // The pathname does not contain a leading '$'
        serverPathname = VersionControlPath.Combine(VersionControlPath.RootFolder, pathname);
        // The pathname is valid.
    }
}
catch
{
    Response.StatusCode = 404;
    Response.End();
}

// The maximum number of changes to return per query
int maxCheckinCount = 50;

string rssVersion = "2.0";
string rssTtl = "5";
string rssLanguage = "en-US";
string rssLink = Request.Url.ToString();
string rssTitle = "Team Foundation RSS Feed for Source Code Control Checkins";
string rssGenerator = "Sample RSS Feed Generator for Team Foundation";
string rssDescription = "<p>This feed provides information on Team Foundation Checkins. Each Team Foundation checkin is manifested as a changeset. The changesets that have been created recently are listed here.</p><p>This feed contains the most recent <i>{0}</i> checkin(s).</p>";
string rssItemOnBehalfOf = "(on behalf of {0}) ";
string rssItemTitle = "Checkin {0} [{1} items]";
string rssNoItemsAvailableDescription = "An error occurred obtaining the latest checkin information from Team Foundation. Try again later.";
string rssItemDescription = "<p><a href=\"{5}\">Changeset {0}</a> was checked in by <i>{1} {2}</i>on {3}. This checkin includes changes to {4} item(s).</p><p>You can view the details of the checkin by selecting the provided link.</p>.";
string exceptionMessage = "<p>An exception occurred while getting updated information from Team Foundation; the detailed exception message is <i>{0}</i></p>";
string itemNotFoundErrorMessage = "<p>There were no items found.</p>";
string accessDeniedErrorMessage = "<p>You do not have permission to obtain the Team Foundation checkin information.</p>";
string otherErrorMessage = "<p>An error occurred. This may be a transient error or a permanent one. Please check the event log for messages from VSTF Source Code Control</p>";

Response.ContentType = "text/xml";
XmlTextWriter xt = new XmlTextWriter(Response.OutputStream, null);
// Begin creating the XML document
xt.WriteStartElement("rss");
xt.WriteAttributeString("version", rssVersion);
xt.WriteStartElement("channel");
xt.WriteElementString("title", rssTitle);
xt.WriteElementString("ttl", rssTtl);
xt.WriteElementString("link", rssLink);
xt.WriteElementString("pubDate", DateTime.Now.ToString());
xt.WriteElementString("language", rssLanguage);
xt.WriteElementString("generator", rssGenerator);
try
{
    RecursionType recursionType = RecursionType.Full;


    // Obtain the list of changes from the mid-tier; the number of changes is reported in
    // the channel description.
    IEnumerable changesetEnum = null;
    try
    {
        TeamFoundationServer Tfs = null;
        object cacheEntry = Context.Cache["TeamFoundationServer"];
        if (cacheEntry == null)
        {
            // Note: only works on localhost
            Tfs = new TeamFoundationServer("http://localhost:8080");
            Context.Cache["TeamFoundationServer"] = Tfs;
        }
        else
        {
            Tfs = (TeamFoundationServer) cacheEntry;
        }
        VersionControlServer Vcs = (VersionControlServer) Tfs.GetService(typeof(VersionControlServer));
        // Return changes
        changesetEnum = Vcs.QueryHistory(serverPathname,  // on this item
                                         VersionSpec.Latest, // item version
                                         0,               // that are not deleted
                                         recursionType,   // at or below this item
                                         null,            // user
                                         null,            // start version
                                         null,            // stop version
                                         maxCheckinCount, // Up to this many changes
                                         true,            // include changes
                                         false);

        int changeCount = 0;
        foreach (Changeset change in changesetEnum)
        {
            changeCount++;
        }
        xt.WriteElementString("description", String.Format(rssDescription, changeCount));
    }
    catch (Exception e)
    {
        if (e is ItemNotFoundException)
        {
            rssNoItemsAvailableDescription += itemNotFoundErrorMessage;
        }
        else
        {
            rssNoItemsAvailableDescription += otherErrorMessage;
        }
        rssNoItemsAvailableDescription += String.Format(exceptionMessage, e.Message);
        xt.WriteElementString("description", rssNoItemsAvailableDescription);
    }

    xt.WriteEndElement(); // channel

    // Create an item for each returned changeset.
    foreach (Changeset change in changesetEnum)
    {
        xt.WriteStartElement("item");
        string onBehalfOf = null;

        // Include the committer if it differs from the changeset owner.
        // This occurs when a proxy agent performs the checkin.
        if (!change.Owner.Equals(change.Committer))
        {
            onBehalfOf = String.Format(rssItemOnBehalfOf, change.Owner);
        }

        xt.WriteElementString("title", String.Format(rssItemTitle,
                                                     change.ChangesetId,
                                                     change.Changes.Length));

        string csLink = HttpUtility.HtmlEncode(new ChangesetUri(
                                                     String.Format("{0}://{1}:{2}",
                                                                  Request.Url.Scheme,
                                                                  Request.Url.Host,
                                                                  Request.Url.Port),
                                                     change.ChangesetId,
                                                     UriType.Extended).ToUrl());

        xt.WriteElementString("description", String.Format(rssItemDescription,
                                                           change.ChangesetId,
                                                           change.Committer,
                                                           onBehalfOf,
                                                           change.CreationDate,
                                                           change.Changes.Length,
                                                           csLink));
        xt.WriteElementString("link", csLink);
        xt.WriteElementString("author", onBehalfOf == null ? change.Owner : change.Committer);
        xt.WriteElementString("pubDate", change.CreationDate.ToString());
        xt.WriteElementString("guid", change.ChangesetId.ToString());
        xt.WriteEndElement(); // item
    }
}
catch (Exception e)
{
    Response.StatusCode = 404;
    Response.End();
}
finally
{
    xt.Close();
    if (throttleRequests)
    {
        Context.Cache[Request.UserHostAddress] = Environment.TickCount;
    }
}
%>

Published Wednesday, July 27, 2005 1:23 PM by jefflu

Comments

# Watching changes via RSS feeds from VSS / VSTS

I've got a little home-grown code that I hacked together, it runs every 30 minutes and generates an XML...
Thursday, July 28, 2005 7:30 AM by Simon Thorneycroft and Jonathan Hodgson

# VSTS Links - 8/1/2005

Eric Jarvi - VSTS Tip: Branching Source Code

Eric discusses what to do and not do when branching source...
Monday, August 01, 2005 10:33 AM by Team System News

# Version Control RSS Feed

Recently, I wrote about a Team Foundation RSS feed. There may be a change required if you're seeing ASP.NET...
Tuesday, August 09, 2005 7:47 AM by jefflu's WebLog

# Team Foundation Notification RSS feeds? Definitely!

I didn't realize this yesterday when I blogged about RSS checkin notifications yesterday, but Jeff has...
Tuesday, August 09, 2005 10:25 AM by John Lawrence (MSFT)

# Team Build notification tool

As we go on developing the product we frequently feel strong about doing new things around&amp;nbsp;our product...
Tuesday, August 09, 2005 11:07 AM by abhinaba's WebLog

# Team Build notification tool

As we go on developing the product we frequently feel strong about doing new things around&amp;nbsp;our product...
Tuesday, August 09, 2005 11:16 AM by abhinaba's WebLog

# Team Build RSS Feed

&amp;lt;Update: After some complains that it is difficult to cut paste code out of the blog, I have zipped...
Friday, April 21, 2006 2:43 PM by I know the answer (it's 42)

# Interesante ejemplo de uso del API de Team System

He encontrado un ejemplo muy interesante sobre como utilizar el API de Team System para construir interesantes...
Friday, May 05, 2006 5:55 AM by La masa, el ladrilo, la bota, el bocadillo...

# Team Build RSS Feed

&lt;Update: After some complains that it is difficult to cut paste code out of the blog, I have zipped

Thursday, August 09, 2007 11:24 PM by I know the answer (it's 42)

# Team Foundation Server и RSS

Любопытно, но, похоже, пока еще никто не реализовал полноценную подписку на события TFS (eventing service)

Tuesday, June 24, 2008 12:40 PM by Дмитрий Лапшин
Anonymous comments are disabled
 
Page view tracker