Created
February 4, 2011 21:00
-
-
Save Vaccano/811759 to your computer and use it in GitHub Desktop.
ProcessTemplate.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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