PageRenderTime 79ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/Watcher Plugins/Team Foundation Server/ProcessResult.cs

#
C# | 231 lines | 150 code | 25 blank | 56 comment | 21 complexity | 2d87cde0ab40602740571b1502f99c02 MD5 | raw file
Possible License(s): LGPL-2.1, CPL-1.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.Specialized;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Security;
  10. using System.Text;
  11. using System.Windows.Forms;
  12. using System.Xml;
  13. using System.Xml.Linq;
  14. using Microsoft.TeamFoundation;
  15. using Microsoft.TeamFoundation.Client;
  16. using Microsoft.TeamFoundation.Common;
  17. using Microsoft.TeamFoundation.WorkItemTracking.Client;
  18. using CasabaSecurity.Web.Watcher;
  19. using CasabaSecurity.Web.Watcher.Collections;
  20. namespace CasabaSecurity.Web.Watcher.TeamFoundation
  21. {
  22. public partial class TeamFoundationOutputPlugin : WatcherOutputPlugin
  23. {
  24. #region Private Method(s)
  25. /// <summary>
  26. /// This method exports a single item.
  27. /// </summary>
  28. /// <remarks>TODO: Standards Compliance Handling?</remarks>
  29. private void ExportResult(WatcherResult watcherResult)
  30. {
  31. WatcherEngine.ProgressDialog.UpdateProgress("Verifying work item type...");
  32. // Verify the work item type exists in the project (e.g., "Bug")
  33. if (_adapter.Project.WorkItemTypes.Contains(_adapter.Configuration.ExportMap.Type) == false)
  34. {
  35. String s = String.Format("Required work item \"{0}\" does not exist in the work item template.", _adapter.Configuration.ExportMap.Type);
  36. Trace.TraceError(s);
  37. throw new WatcherException(s); // TODO: Message box title: Error
  38. }
  39. // Create an instance of the work item
  40. WatcherEngine.ProgressDialog.UpdateProgress(String.Format("Creating work item \"{0}\"...", watcherResult.Title));
  41. WorkItem workItem = new WorkItem(_adapter.Project.WorkItemTypes[_adapter.Configuration.ExportMap.Type]);
  42. #if DEBUG
  43. Debug.WriteLine(String.Format("Work item \"{0}\" fields:", workItem.Title));
  44. foreach (Field field in workItem.Fields)
  45. {
  46. Debug.WriteLine(String.Format("\tRequired: {0}; Reference Name: {1}", field.IsRequired, field.ReferenceName));
  47. }
  48. #endif
  49. // Ensure fields required by the work item template have been defined in the XML map
  50. try { ValidateWorkItemFields(workItem); }
  51. catch (WatcherException ex)
  52. {
  53. String s = String.Format("Unable to validate work item fields:\r\n\r\n{0}", ex.Message);
  54. Trace.TraceError(s);
  55. throw new WatcherException(s, ex); // TODO: Message box title: Error
  56. }
  57. // Map the Watcher result information to the TFS template (including SDL fields)
  58. try { PopulateWorkItem(workItem, watcherResult); }
  59. catch (WatcherException ex)
  60. {
  61. String s = String.Format("Unable to populate work item fields:\r\n\r\n{0}", ex.Message);
  62. Trace.TraceError(s);
  63. throw new WatcherException(s, ex); // TODO: Message box title: Error
  64. }
  65. WatcherEngine.ProgressDialog.UpdateProgress("Saving work item...");
  66. // Save the new work item
  67. // TODO: Allow the user to continue on non-fatal failures
  68. try { workItem.Save(); }
  69. catch (ValidationException ex)
  70. {
  71. String s = String.Format("Unable to save the work item template:\r\n\r\n{0}", ex.Message);
  72. Trace.TraceError(s);
  73. throw new WatcherException(s, ex); // TODO: Message box title: Error
  74. }
  75. }
  76. /// <summary>
  77. /// This method maps Watcher fields to SDL fields.
  78. /// </summary>
  79. /// <remarks>
  80. /// TODO: Mappings should be pulled from the user-configurable XML file.
  81. /// TODO: Description should be converted to HTML and include the URI.
  82. /// TODO: Mappings should work even if the configuration file does not exist.
  83. /// </remarks>
  84. /// <param name="workItem">The TFS work item.</param>
  85. /// <param name="watcherResult">The Watcher finding.</param>
  86. private void PopulateWorkItem(WorkItem workItem, WatcherResult watcherResult)
  87. {
  88. // Set defaults
  89. //
  90. // Set the origin to "Watcher"
  91. if (workItem.Fields.Contains("Microsoft.SDL.Security.Origin")) // TODO: optimize. use single string
  92. {
  93. workItem["Microsoft.SDL.Security.Origin"] = "Watcher Web Security Tool (Casaba Security, LLC.)";
  94. }
  95. // Set the title of the work item.
  96. //
  97. // If the configuration contains a destination entry of System.Title and is sourced by
  98. // the CasabaSecurity.Watcher.Title, use a Watcher-default title. If the source does
  99. // not exist, use the default value specified in the configuration.
  100. //
  101. foreach (TeamFoundationConfiguration.FindingMapEntry entry in _adapter.Configuration.ExportMap.Mappings)
  102. {
  103. // TODO: This is the case where source and destination are specified
  104. // TODO: Case 2: Where destination and default value are specified
  105. Debug.Assert(entry.Destination != null, "Destination must always be specified in the mapping.");
  106. if (entry.Destination == null)
  107. {
  108. Trace.TraceError("TeamFoundationMapEntry contains a destination that is null. This should never happen.");
  109. throw new WatcherException("TeamFoundationMapEntry contains a destination that is null."); // TODO: review
  110. }
  111. // The destination field name must exist in the work item
  112. // TODO: this should have already been checked
  113. if (workItem.Fields.Contains(entry.Destination) == false)
  114. {
  115. Trace.TraceError("Destination name does not exist in the work item template."); // TODO: single string
  116. throw new WatcherException("Destination name does not exist in the work item template."); // TODO: be more descript
  117. }
  118. // XXX Enumerate each source, if it matches one we know about, add our version of the value to the field.
  119. // XXX Otherwise, if there is no match, it's an error.
  120. // XXX TODO: what if this is null?
  121. switch (entry.Source)
  122. {
  123. case "CasabaSecurity.Web.Watcher.Title":
  124. workItem[entry.Destination] = String.Format("{0}", watcherResult.Title);
  125. break;
  126. // TODO: The Watcher description should be translated to HTML prior to setting this field.
  127. case "CasabaSecurity.Web.Watcher.Description":
  128. workItem[entry.Destination] = watcherResult.Description;
  129. break;
  130. case "CasabaSecurity.Web.Watcher.Origin":
  131. workItem[entry.Destination] = "Watcher Web Security Tool (Casaba Security, LLC.)";
  132. break;
  133. case "CasabaSecurity.Web.Watcher.Severity":
  134. workItem[entry.Destination] = _adapter.Configuration.GetTranslatedValue("CasabaSecurity.Web.Watcher.Severity", watcherResult.Severity.ToString()); //XXX TODO
  135. break;
  136. // If no source field exists for this destination, use the default value defined in the mapping
  137. default:
  138. // TODO: ensure when reading mapping that the above fields are the only valid fields
  139. // TODO: ensure that only source/destination and destination/default value pairs are specified.
  140. // TODO: ensure DefaultValue is not null?
  141. workItem[entry.Destination] = entry.DefaultValue;
  142. break;
  143. }
  144. }
  145. }
  146. /// <summary>
  147. /// This method ensures the fields required by the Work Item Template have been defined in the XML map.
  148. /// </summary>
  149. /// <param name="workItem">The Team Foundation work item whose fields are to be examined.</param>
  150. private void ValidateWorkItemFields(WorkItem workItem)
  151. {
  152. foreach (Field field in workItem.Fields)
  153. {
  154. // If the WIT field is required and does not have a default value
  155. // TODO: ensure the values were are submitting are of the correct type and enumeration
  156. // TODO: unsure about not requiring date times. System.CreatedDate seems to be required but is not labeled as such in the WIT.
  157. if (field.IsRequired && field.FieldDefinition.FieldType != FieldType.DateTime && field.Value == null)
  158. {
  159. Boolean mapContainsRequiredField = false;
  160. // Enumerate the entries in the map and search for the required field
  161. foreach (TeamFoundationConfiguration.FindingMapEntry mapEntry in _adapter.Configuration.ExportMap.Mappings)
  162. {
  163. // The destination comes from the XML file defining the mapping, and the
  164. // Reference Name is the fully-qualified field name of the destination.
  165. if (mapEntry.Destination == field.ReferenceName)
  166. {
  167. mapContainsRequiredField = true;
  168. break;
  169. }
  170. }
  171. // Required field was not found
  172. if (mapContainsRequiredField == false)
  173. {
  174. String s = String.Format("Required field \"{0}\" does not exist in the Watcher Team Foundation Configuration file.", field.ReferenceName);
  175. Trace.TraceError(s);
  176. throw new WatcherException(s);
  177. }
  178. }
  179. }
  180. List<String> warnings = new List<String>();
  181. // Make sure destination fields specified in the XML file exist in the Work Item Template.
  182. foreach (TeamFoundationConfiguration.FindingMapEntry mapEntry in _adapter.Configuration.ExportMap.Mappings)
  183. {
  184. if (workItem.Fields.Contains(mapEntry.Destination) == false)
  185. {
  186. // WIT does not contain a field defined in the XML
  187. String s = String.Format("Field '{0}' does not exist in Team Foundation Server Work Item Template '{1}'. Please ensure the field is spelled correctly in the Team Foundation configuration file, or remove it altogether.", mapEntry.Destination, workItem.Project.Name);
  188. Trace.TraceWarning(s);
  189. warnings.Add(s);
  190. }
  191. }
  192. // If there are warnings, display them. // TODO: make sure the operation is allowed to continue
  193. if (warnings.Count > 0)
  194. {
  195. // Create the display string
  196. StringBuilder sb = new StringBuilder(warnings.Count);
  197. foreach (String s in warnings)
  198. {
  199. sb.AppendFormat("{0}\r\n\r\n", s);
  200. }
  201. throw new WatcherException(sb.ToString());
  202. }
  203. }
  204. #endregion
  205. }
  206. }