using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Windows.Forms;
using System.Xml;
using System.Collections;
using System.IO;
namespace TeamSystemLabs
{
public class Strings
{
public static string policyType = “XMLDocumentation policy”;
public static string policyDescription = “This policy will check if the developer has XML documentation turned on for a C# project so the build won’t fail on missing XML files.”;
public static string policyInstallationInstructions = “To install this policy, download it from the project portal.”;
public static string policyQuestion = “Do you want to turn on the XMLDocumentation policy?”;
public static string policyTypeDescription = “XML Documentation Policy”;
public static string policyDisposedMessage = “Policy Object has been disposed.”;
public static string policyHelp = “Help for policy”;
public static string policyFailureHelpText = “Go to the property page of the c# project and turn on XML Documentation”;
public static string policyViolationMessage = “You must turn on XML documentation in the c# project file {0}.”;
public static string vsDotNetDefaultNamespace = “http://schemas.microsoft.com/developer/msbuild/2003”;
public static string tab = “t”;
}
[Serializable]
public class XmlDocumentationPolicy: IPolicyDefinition, IPolicyEvaluation
{
#region IPolicyDefinition Members
// This is the description of a defined policy that is displayed in the UI.
public string Description
{
get { return Strings.policyDescription; }
}
public bool CanEdit
{
get { return true; }
}
// This method is invoked by the policy framework when the user creates a new checkin
// policy or edits an existing checkin policy. We can use this as an opportunity to
// display UI specific to this policy type allowing the user to change the parameters
// of the policy.
public bool Edit(IPolicyEditArgs policyEditArgs)
{
if (MessageBox.Show(policyEditArgs.Parent, Strings.policyQuestion, “XmlDocument Policy”, MessageBoxButtons.YesNo)
== DialogResult.Yes)
{
return true;
}
return false;
}
// This is a string that is stored with the policy definition on the source
// control server. If a user does not have our policy plugin installed, this string
// will be displayed. We can use this as an opportunity to explain to the user
// how they might go about installing our policy plugin.
public string InstallationInstructions
{
get { return Strings.policyInstallationInstructions; }
}
// This string is the type of our policy. It will be displayed to the user in a list
// of all installed policy types when they are creating a new policy.
public string Type
{
get { return Strings.policyType; }
}
// This string is a description of the type of our policy. It will be displayed to the
// user when they select our policy type in the list of policies installed on the system
// as mentioned above.
public string TypeDescription
{
get { return Strings.policyTypeDescription; }
}
#endregion
#region IPolicyEvaluation Members
// This method performs the actual evaluation. It is called by the policy framework at various points in time
// when policy should be evaluated. In this example, we invoke this method ourselves when various asyc
// events occur that may have invalidated the current list of failures.
public PolicyFailure[] Evaluate()
{
// check the csproj file if xml documentation is turned on.
ArrayList failures = IsXMLDocumentationTurnedOn();
if (failures.Count == 0)
return m_noFailures;
else
{
PolicyFailure[] toReturn = new PolicyFailure[failures.Count];
failures.CopyTo(toReturn);
return toReturn;
}
}
private ArrayList IsXMLDocumentationTurnedOn()
{
// find if there is a csproj file involved
ArrayList csprojFiles = new ArrayList();
ArrayList failures = new ArrayList();
foreach(PendingChange change in
m_pendingCheckin.PendingChanges.AllPendingChanges)
{
if (change.FileName.EndsWith(“csproj”))
{
// now get the file name including its path
csprojFiles.Add(change.LocalItem);
}
}
if (csprojFiles.Count >0)
{
// load the file into the XML document and search for the documentation property
// the tag looks like this : <DocumentationFile>binDebugXMLDocumentationPolicy.XML</DocumentationFile>
foreach (string csprojFile in csprojFiles)
{
XmlDocument csprojXml = new XmlDocument();
csprojXml.Load(csprojFile);
// if the node is there we know the documentation is enabled
XmlNamespaceManager xmlNS = new XmlNamespaceManager(csprojXml.NameTable);
xmlNS.AddNamespace(“a”,Strings.vsDotNetDefaultNamespace);
XmlNode n = csprojXml.SelectSingleNode(“//a:DocumentationFile”, xmlNS);
if ((n == null) || (n.InnerText.Length== 0))
{
failures.Add(new
PolicyFailure(string.Format(Strings.policyViolationMessage,
csprojFile), this));
}
}
}
return failures;
}
// This method is called by the policy framework when the plugin is instantiated.
// This gives us an opportunity to capture the pendingCheckin object and register
// for notification of changes in the set of pending changes being checked in.
public void Initialize(IPendingCheckin pendingCheckin)
{
m_pendingCheckin = pendingCheckin;
m_pendingCheckin.PendingChanges.CheckedPendingChangesChanged += new
EventHandler(PendingChanges_CheckedPendingChangesChanged);
}
// This method is called as our policy object is being discarded. We’ll unregister for
// events that were registered in the Initialize() method.
public void Dispose()
{
m_pendingCheckin.PendingChanges.CheckedPendingChangesChanged -= new
EventHandler(PendingChanges_CheckedPendingChangesChanged);
m_pendingCheckin = null;
}
// This is the event handler for changes in the selected source files being checked in.
// As the user checks and unchecks files for checkin from the pending checkin tool window
// or checkin dialog, this event handler will be invoked giving the plugin an opportunity
// to update the policy failures.
private void PendingChanges_CheckedPendingChangesChanged(Object sender, EventArgs e)
{
OnPolicyStateChanged(Evaluate());
}
// This event is subscribed to by the policy framework and gives us a mechanism to
// notify the framework when things happen asynchronously that affect policy compliance.
public event PolicyStateChangedHandler PolicyStateChanged;
// This method will notify the policy framework that policy compliance has
// changed and needs to be updated in the UI.
private void OnPolicyStateChanged(PolicyFailure[] failures)
{
if (PolicyStateChanged != null)
{
PolicyStateChanged(this, new PolicyStateChangedEventArgs(failures, this));
}
}
// This method is called if the user double-clicks on a policy failure in the UI.
// We can handle this as we please, potentially prompting the user to perform
// some activity that would eliminate the policy failure.
public void Activate(PolicyFailure failure)
{
MessageBox.Show(Strings.policyFailureHelpText);
}
// This method is called if the user presses F1 when a policy failure is active in the UI.
// We can handle this as we please, displaying help in whatever format is appropriate.
// For this example, we’ll just pop up a dialog.
public void DisplayHelp(PolicyFailure failure)
{
MessageBox.Show(Strings.policyFailureHelpText,
“XML Documentation Policy Help”);
}
[NonSerialized]
public static readonly PolicyFailure[] m_noFailures = new PolicyFailure[0];
private IPendingCheckin m_pendingCheckin = null;
#endregion
}
}