Skip to content

Instantly share code, notes, and snippets.

@Vaccano
Created February 4, 2011 21:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Vaccano/811759 to your computer and use it in GitHub Desktop.
Save Vaccano/811759 to your computer and use it in GitHub Desktop.
ProcessTemplate.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
namespace TFSLBALib
{
/// <summary>
/// This class handles a Team System Process Template
/// You can open locally stored Process Template or from a Zip File
/// A set of methods gives you the possibility to interact with the Process Template's content
/// Helper method let you repack the Process Template, upload it in Team System
/// </summary>
public class ProcessTemplate : IDisposable
{
#region Data Members
/// <summary>
/// Zip File representing the packed version of the Process Template
/// </summary>
FileInfo ZipFile = null;
/// <summary>
/// Directory where the Process Template is stored
/// </summary>
DirectoryInfo RootDir = null;
/// <summary>
/// If true, the RootDir is temporary and contains the unpack version of the ZipFile
/// If false, the RootDir is a Working Directory
/// </summary>
bool RootDirIsTemp = false;
/// <summary>
/// If true, the Zipfile is temporary and should be deleted upon object's release
/// </summary>
bool ZipFileIsTemp = false;
#endregion
#region Constructors
/// <summary>
/// Create a Process Template object from a directory containing the template's files
/// </summary>
/// <param name="processtemplaterootdir">Root Directory of the Process Template</param>
public ProcessTemplate(DirectoryInfo processtemplaterootdir)
{
// Checkings
if ((processtemplaterootdir==null) || (processtemplaterootdir.Exists==false)) throw new ArgumentException("Invalid Argument", "processtemplaterootdir");
// Assign the directory
RootDir = processtemplaterootdir;
RootDirIsTemp = false;
}
/// <summary>
/// Create a Process Template object from a Zip File
/// </summary>
/// <param name="processtemplatezipfile">The Zip File containing the packed directory of the Process Template</param>
/// <remarks>This construction is used typically with the file returned by IProcessTemplates.GetTemplateData()</remarks>
public ProcessTemplate(FileInfo processtemplatezipfile)
{
// Checkings
if (processtemplatezipfile.Exists == false) throw new ArgumentException("File doesn't exist", "processtemplatezipfile");
// Load from the Zip file
LoadFromZip(processtemplatezipfile);
// Set the FileInfo
ZipFile = processtemplatezipfile;
}
/// <summary>
/// Create a Process Template object from a existing one in a given Team Foundation Server
/// </summary>
/// <param name="tfs">The TFS where the Process Template is stored</param>
/// <param name="processtemplatename">The Name of the Process Template</param>
/// <remarks>The name can be obtained from the TeamplateHeader.Name property.</remarks>
public ProcessTemplate(TeamFoundationServer tfs, string processtemplatename)
{
// Checkings
if (tfs == null) throw new ArgumentException("Null TFS object", "tfs");
// Get the Process Template interface
IProcessTemplates ptp = (IProcessTemplates)tfs.GetService(typeof(IProcessTemplates));
// Get the template Zipfile
try
{
int tpi = ptp.GetTemplateIndex(processtemplatename);
String zippathfilename = ptp.GetTemplateData(tpi);
// Zip File is temporary
ZipFileIsTemp = true;
// Set the FileInfo
ZipFile = new FileInfo(zippathfilename);
// Load from zip
LoadFromZip(ZipFile);
}
catch (Exception e)
{
throw new Exception(String.Format("Couldn't find the Process Template nammed: {0}", processtemplatename), e);
}
}
#endregion
#region Helpers
private void LoadFromZip(FileInfo processtemplatezipfile)
{
if (processtemplatezipfile.Exists == false) throw new ArgumentException("File doesn't exist", "processtemplatezipfile");
try
{
// Construct a temporary directory
RootDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));
RootDirIsTemp = true;
// Unpack the Zip File in the temporary directory
FastZip fz = new FastZip();
fz.ExtractZip(processtemplatezipfile.FullName, RootDir.FullName, "");
}
catch (Exception e)
{
throw new Exception("Couldn't unpack the Process Template", e);
}
// Look for the "ProcessTemplate.xml" file in the root
FileInfo rootxml = new FileInfo(Path.Combine(RootDir.FullName, "ProcessTemplate.xml"));
if (rootxml.Exists == false) throw new ArgumentException("Given Archive is not a Process Template", "processtemplatezipfile");
}
private XmlDocument LoadXmlDoc(String relpath)
{
XmlDocument xml = new XmlDocument();
xml.Load(Path.Combine(RootDir.FullName, relpath));
return xml;
}
#endregion
#region Process Template Properties
public String Name
{
get
{
try
{
return ProcessTemplateDoc.DocumentElement.SelectSingleNode("metadata/name").InnerText;
}
catch (Exception e)
{
}
return "";
}
set
{
try
{
XmlNode name = ProcessTemplateDoc.DocumentElement.SelectSingleNode("metadata/name");
name.InnerText = value;
}
catch (Exception e)
{
}
}
}
public String Description
{
get
{
try
{
return ProcessTemplateDoc.DocumentElement.SelectSingleNode("metadata/description").InnerText;
}
catch (Exception e)
{
}
return "";
}
set
{
try
{
XmlNode desc = ProcessTemplateDoc.DocumentElement.SelectSingleNode("metadata/description");
desc.InnerText = value;
}
catch (Exception e)
{
}
}
}
#endregion
#region Main XML Access
private XmlDocument ProcessTemplateDoc
{
get
{
if (_ProcessTemplateDoc!=null) return _ProcessTemplateDoc;
_ProcessTemplateDoc = LoadXmlDoc("ProcessTemplate.xml");
return _ProcessTemplateDoc;
}
}
private XmlDocument _ProcessTemplateDoc = null;
private bool _ProcessTemplateDocDirty = false;
private XmlDocument WorkItemsDoc
{
get
{
if (_WorkItemsDoc!=null) return _WorkItemsDoc;
_WorkItemsDoc = LoadXmlDoc("WorkItem Tracking\\WorkItems.xml");
return _WorkItemsDoc;
}
}
private XmlDocument _WorkItemsDoc = null;
private bool _WorkItemsDocDirty = false;
#endregion
/// <summary>
/// Dispose implementation
/// </summary>
/// <remarks>Free resources, delete temporary directory content if required</remarks>
public void Dispose()
{
// Delete the directory if it's temporary
if (RootDirIsTemp)
{
RootDir.Delete(true);
}
// Delete the Zip if it's temporary too
if (ZipFileIsTemp)
{
ZipFile.Delete();
}
}
#region Work Item access
public String[] GetWITList()
{
List<String> witlist = new List<string>();
// Get the Work Item Type definitions
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"WITs\"]/taskXml/WORKITEMTYPES/WORKITEMTYPE");
foreach (XmlNode node in wilist)
{
try
{
XmlElement xel = node as XmlElement;
string filename = xel.GetAttribute("fileName");
XmlDocument witdoc = LoadXmlDoc(filename);
// Get the name of the Work Item
xel = witdoc.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
witlist.Add(xel.GetAttribute("name"));
}
catch (Exception)
{
}
}
return witlist.ToArray();
}
public String[] GetWIQLList()
{
List<String> wiqllist = new List<string>();
// Get the Work Item Queries on the main node
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"Queries\"]/taskXml/QUERIES/Query");
foreach (XmlNode node in wilist)
{
try
{
XmlElement xel = node as XmlElement;
wiqllist.Add(xel.GetAttribute("name"));
}
catch (Exception)
{
}
}
// Get the work item queries in any folders.
XmlNodeList wiqFolders = WorkItemsDoc.SelectNodes("tasks/task[@id=\"Queries\"]/taskXml/QUERIES/QueryFolder");
foreach (XmlNode wiqFolder in wiqFolders)
{
XmlElement folderElement = wiqFolder as XmlElement;
string folderName = folderElement.GetAttribute("name");
// Get all the queries in the folder
foreach (XmlNode wiqInFolder in wiqFolder)
{
try
{
XmlElement queryElement = wiqInFolder as XmlElement;
wiqllist.Add("«" + folderName + @"» " + queryElement.GetAttribute("name"));
}
catch (Exception)
{
}
}
}
return wiqllist.ToArray();
}
public XmlDocument GetWITDefinition(String witname)
{
// Get the Work Item Type definitions
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"WITs\"]/taskXml/WORKITEMTYPES/WORKITEMTYPE");
foreach (XmlNode node in wilist)
{
try
{
XmlElement xel = node as XmlElement;
string filename = xel.GetAttribute("fileName");
XmlDocument witdoc = LoadXmlDoc(filename);
// Get the name of the Work Item
xel = witdoc.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
if (witname == xel.GetAttribute("name"))
{
return witdoc;
}
}
catch (Exception)
{
}
}
return null;
}
public XmlDocument GetWIQLDefinition(String wiqlname)
{
// See if the query is in a folder
if (!wiqlname.Contains("»"))
{
// Get the Query definitions
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"Queries\"]/taskXml/QUERIES/Query");
foreach (XmlNode node in wilist)
{
try
{
XmlElement xel = node as XmlElement;
if (wiqlname == xel.GetAttribute("name"))
{
string wiqlpfn = xel.GetAttribute("fileName");
return LoadXmlDoc(wiqlpfn);
}
}
catch (Exception)
{
}
}
}
// Get queries that are in folders.
else
{
// Parse out the name and folder of the query
string folderName;
string queryName;
try
{
folderName = wiqlname.Split('»')[0].Remove(0, 1).Trim();
queryName = wiqlname.Split('»')[1].Trim();
}
catch (Exception)
{
folderName = "";
queryName = "";
MessageBox.Show("Could not parse query " + wiqlname);
}
// Get the work item queries in any folders.
XmlNodeList wiqFolders = WorkItemsDoc.SelectNodes("tasks/task[@id=\"Queries\"]/taskXml/QUERIES/QueryFolder");
foreach (XmlNode wiqFolder in wiqFolders)
{
XmlElement folderElement = wiqFolder as XmlElement;
string currentFolderName = folderElement.GetAttribute("name");
if (currentFolderName == folderName )
{
// Get all the queries in the folder
foreach (XmlNode wiqInFolder in wiqFolder)
{
try
{
XmlElement xel = wiqInFolder as XmlElement;
if (queryName == xel.GetAttribute("name"))
{
string wiqlpfn = xel.GetAttribute("fileName");
return LoadXmlDoc(wiqlpfn);
}
}
catch (Exception)
{
}
}
}
}
}
return null;
}
public bool AddWorkItemType(XmlDocument witdoc, bool updateifexist)
{
// Get the name of the WIT
XmlElement xel = witdoc.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
String witname = xel.GetAttribute("name");
// Loop through the WIT list to find a possible existing one
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"WITs\"]/taskXml/WORKITEMTYPES/WORKITEMTYPE");
foreach (XmlNode node in wilist)
{
try
{
xel = node as XmlElement;
string filename = xel.GetAttribute("fileName");
XmlDocument curwitdoc = LoadXmlDoc(filename);
// Get the name of the Work Item
xel = curwitdoc.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
// Do we found the one to update
if (xel.GetAttribute("name") == witname)
{
// Returns an error if we are not allowed to update
if (updateifexist == false) return false;
// Replace the file
witdoc.Save(Path.Combine(RootDir.FullName, filename));
return true;
}
}
catch (Exception)
{
}
}
// It's a new work item, add it
string witstrippedname = witname.Replace(" ", "");
string newwitfilename = String.Format("{0}{1}.xml", @"WorkItem Tracking\TypeDefinitions\", witstrippedname);
witdoc.Save(Path.Combine(RootDir.FullName, newwitfilename));
// Add the reference in the WorkItemsDoc
XmlNode wits = WorkItemsDoc.SelectSingleNode("tasks/task[@id=\"WITs\"]/taskXml/WORKITEMTYPES");
XmlElement witel = WorkItemsDoc.CreateElement("WORKITEMTYPE");
witel.SetAttribute("fileName", newwitfilename);
wits.AppendChild(witel);
// Make the WorkItems.xml dirty
_WorkItemsDocDirty = true;
return true;
}
public bool AddQuery(String wiqlname, XmlDocument wiqldoc, bool updateifexist)
{
// Loop through the WIQL list to find a possible existing one
XmlNodeList wilist = WorkItemsDoc.SelectNodes("tasks/task[@id=\"Queries\"]/taskXml/QUERIES/Query");
foreach (XmlNode node in wilist)
{
try
{
// Get the current Query Element
XmlElement xel = node as XmlElement;
// Do we found the one to update
if (xel.GetAttribute("name") == wiqlname)
{
// Returns an error if we are not allowed to update
if (updateifexist == false) return false;
// Get the filename of the XML file storing the query
String filename = xel.GetAttribute("fileName");
// Replace the file
wiqldoc.Save(Path.Combine(RootDir.FullName, filename));
return true;
}
}
catch (Exception)
{
}
}
// It's a new Query, add it
string wiqlstrippedname = wiqlname.Replace(" ", "");
string newwiqlfilename = String.Format("{0}{1}.wiq", @"WorkItem Tracking\Queries\", wiqlstrippedname);
string fullpathname = Path.Combine(RootDir.FullName, newwiqlfilename);
wiqldoc.Save(fullpathname);
// Add the reference in the WorkItemsDoc
XmlNode wiqls = WorkItemsDoc.SelectSingleNode("tasks/task[@id=\"Queries\"]/taskXml/QUERIES");
XmlElement wiqlel = WorkItemsDoc.CreateElement("Query");
wiqlel.SetAttribute("name", wiqlname);
wiqlel.SetAttribute("fileName", newwiqlfilename);
wiqls.AppendChild(wiqlel);
// Make the WorkItems.xml dirty
_WorkItemsDocDirty = true;
return true;
}
#endregion
public bool Upload(TeamFoundationServer tfs, bool updateexisting)
{
// Checkings
if (tfs == null) throw new ArgumentException("Null TFS object", "tfs");
// Check if the XML files should be saved
if (_ProcessTemplateDocDirty == true)
{
String pfn = Path.Combine(RootDir.FullName, "ProcessTemplate.xml");
ProcessTemplateDoc.Save(pfn);
_ProcessTemplateDocDirty = false;
}
if (_WorkItemsDocDirty == true)
{
String pfn = Path.Combine(RootDir.FullName, "WorkItem Tracking\\WorkItems.xml");
WorkItemsDoc.Save(pfn);
_WorkItemsDocDirty = false;
}
// Pack the modified process template
FastZip fz = new FastZip();
String newptfile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
fz.CreateZip(newptfile, RootDir.FullName, true, "");
// Get the Process Template interface
IProcessTemplates ptp = (IProcessTemplates)tfs.GetService(typeof(IProcessTemplates));
TemplateHeader[] headers = ptp.TemplateHeaders();
// Check if the template exist or not
int tpi = ptp.GetTemplateIndex(Name);
string metadata = ProcessTemplateDoc.DocumentElement.SelectSingleNode("metadata").OuterXml;
// Create a new template
if (tpi == -1)
{
tpi = ptp.AddTemplate(Name, Description, metadata, "visible");
} else if (updateexisting == false)
{
return false;
}
// Upload the template
ptp.AddUpdateTemplate(Name, Description, metadata, "visible", newptfile);
// Delete the zip file
File.Delete(newptfile);
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment