/// <summary>
        /// Add a hyperlink to the
        /// </summary>
        /// <param name="text">Display text of the hyperlink</param>
        /// <param name="uri">Uri of the hyperlink</param>
        /// <param name="parent">Parent node in the build log</param>
        /// <returns>The new external link containing the supplied hyperlink</returns>
        protected static IExternalLink AddLinkNode(string text, Uri uri, IBuildInformationNode parent)
        {
            var link = parent.Children.AddExternalLink(text, uri);

            link.Save();
            return(link);
        }
        /// <summary>
        /// Analyzes the resulting metrics file and compares the Maintainability Index and Cyclomatic Complexity against the threshold values
        /// </summary>
        /// <param name="member">Name of the member (namespace, module, type...)</param>
        /// <param name="metrics">The metrics for this member</param>
        /// <param name="parent">The parent node in the build log</param>
        private void ProcessMetrics(string member, IEnumerable <Metric> metrics, IBuildInformationNode parent)
        {
            foreach (var metric in metrics)
            {
                int metricValue;
                if (metric != null && !string.IsNullOrEmpty(metric.Value) && int.TryParse(metric.Value, out metricValue))
                {
                    if (metric.Name == MaintainabilityIndex && Convert.ToInt32(metric.Value) < this.MaintainabilityIndexErrorThreshold.Get(this.ActivityContext))
                    {
                        this.FailCurrentBuild();
                        LogBuildError(string.Format("{0} for {1} is {2} which is below threshold ({3})", MaintainabilityIndex, member, metric.Value, this.MaintainabilityIndexErrorThreshold.Get(this.ActivityContext)));
                    }

                    if (metric.Name == MaintainabilityIndex && metricValue < this.MaintainabilityIndexWarningThreshold.Get(this.ActivityContext))
                    {
                        this.PartiallyFailCurrentBuild();
                        LogBuildError(string.Format("{0} for {1} is {2} which is below threshold ({3})", MaintainabilityIndex, member, metric.Value, this.MaintainabilityIndexWarningThreshold.Get(this.ActivityContext)));
                    }

                    if (metric.Name == CyclomaticComplexity && metricValue > this.CyclomaticComplexityErrorThreshold.Get(this.ActivityContext))
                    {
                        this.FailCurrentBuild();
                        this.LogBuildError(string.Format("{0} for {1} is {2} which is above threshold ({3})", CyclomaticComplexity, member, metric.Value, this.CyclomaticComplexityErrorThreshold.Get(this.ActivityContext)));
                    }

                    if (metric.Name == CyclomaticComplexity && metricValue > this.CyclomaticComplexityWarningThreshold.Get(this.ActivityContext))
                    {
                        this.PartiallyFailCurrentBuild();
                        this.LogBuildError(string.Format("{0} for {1} is {2} which is above threshold ({3})", CyclomaticComplexity, member, metric.Value, this.CyclomaticComplexityWarningThreshold.Get(this.ActivityContext)));
                    }

                    AddTextNode(metric.Name + ": " + metric.Value, parent);
                }
            }
        }
        /// <summary>
        /// Add a text node to the build log
        /// </summary>
        /// <param name="text">Display text</param>
        /// <param name="parent">Parent node in the build log</param>
        /// <returns>The new node containing the supplied text</returns>
        protected static IBuildInformationNode AddTextNode(string text, IBuildInformationNode parent)
        {
            IBuildInformationNode childNode = parent.Children.CreateNode();

            childNode.Type = parent.Type;
            childNode.Fields.Add("DisplayText", text);
            childNode.Save();
            return(childNode);
        }
        /// <summary>
        /// Executes the logic for this workflow activity
        /// </summary>
        protected override void InternalExecute()
        {
            this.BuildDetail = this.ActivityContext.GetExtension <IBuildDetail>();
            string generatedFile = "Metrics.xml";

            if (this.GeneratedFileName != null && !string.IsNullOrEmpty(this.GeneratedFileName.Get(this.ActivityContext)))
            {
                generatedFile = Path.Combine(this.BuildDetail.DropLocation, this.GeneratedFileName.Get(this.ActivityContext));
            }

            if (!this.RunCodeMetrics(generatedFile))
            {
                return;
            }

            IActivityTracking     currentTracking = this.ActivityContext.GetExtension <IBuildLoggingExtension>().GetActivityTracking(this.ActivityContext);
            IBuildInformationNode rootNode        = AddTextNode("Processing metrics", currentTracking.Node);

            string fileName = Path.GetFileName(generatedFile);
            string pathToFileInDropFolder = Path.Combine(this.BuildDetail.DropLocation, fileName);

            AddLinkNode(fileName, new Uri(pathToFileInDropFolder), rootNode);

            CodeMetricsReport result = CodeMetricsReport.LoadFromFile(generatedFile);

            if (result == null)
            {
                LogBuildMessage("Could not load metric result file ");
                return;
            }

            foreach (var target in result.Targets)
            {
                var targetNode = AddTextNode("Target: " + target.Name, rootNode);
                foreach (var module in target.Modules)
                {
                    var moduleNode = AddTextNode("Module: " + module.Name, targetNode);
                    this.ProcessMetrics(module.Name, module.Metrics, moduleNode);
                    foreach (var ns in module.Namespaces)
                    {
                        var namespaceNode = AddTextNode("Namespace: " + ns.Name, moduleNode);
                        this.ProcessMetrics(ns.Name, ns.Metrics, namespaceNode);
                        foreach (var type in ns.Types)
                        {
                            var typeNode = AddTextNode("Type: " + type.Name, namespaceNode);
                            this.ProcessMetrics(type.Name, type.Metrics, typeNode);
                            foreach (var member in type.Members)
                            {
                                var memberNode = AddTextNode("Member: " + member.Name, typeNode);
                                this.ProcessMetrics(member.Name, member.Metrics, memberNode);
                            }
                        }
                    }
                }
            }
        }
예제 #5
0
 private void RecurseStepsNode(IBuildInformationNode node, List <IBuildInformationNode> result, int level)
 {
     foreach (IBuildInformationNode childNode in node.Children.Nodes)
     {
         string status    = childNode.Fields["Status"];
         bool   successed = status.ToLower() == "succeeded";
         //if (!successed || (level <= 1))
         {
             result.Add(childNode);
             RecurseStepsNode(childNode, result, level + 1);
         }
     }
 }
예제 #6
0
        private void ChangeBuildAssigment(string teamProject, WorkItem workItem, string buildNumber, bool removeAction)
        {
            IBuildDetail buildDetail = Context.GetBuild(teamProject, buildNumber);

            if (buildDetail == null)
            {
                return;
            }
            try
            {
                List <IBuildInformationNode> nodes             = buildDetail.Information.GetNodesByType("AssociatedWorkItem");
                IBuildInformationNode        associatedWI_Node = nodes.Find(node =>
                {
                    return(node.Fields["WorkItemUri"] == workItem.Uri.ToString());
                });

                if (removeAction)
                {
                    if (associatedWI_Node != null)
                    {
                        associatedWI_Node.Delete();
                    }
                }
                else
                {
                    if (associatedWI_Node == null)
                    {
                        IBuildInformationNode node = buildDetail.Information.CreateNode();
                        node.Type = "AssociatedWorkItem";
                        node.Fields[CoreField.Title.ToString()]      = workItem.Title;
                        node.Fields[CoreField.AssignedTo.ToString()] =
                            workItem.Fields[CoreField.AssignedTo].Value as string;
                        node.Fields["WorkItemUri"] = workItem.Uri.ToString();
                        node.Fields["Status"]      = workItem.State;
                        node.Fields["WorkItemId"]  = workItem.Id.ToString();
                        node.Save();
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(
                    string.Format("Changing build assigment for workitem id: {0} ('{1}') failed, message: {2}",
                                  workItem.Id, workItem.Title, e.Message), "Change build assigment", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }
예제 #7
0
        /// <summary>
        /// Analyzes the resulting metrics file and compares the metrics against the threshold values
        /// </summary>
        /// <param name="parent">The parent node in the build log</param>
        /// <param name="metrics">List of metric values</param>
        /// <param name="thresholds">Thresholds for errors and warnings </param>
        /// <param name="fullyQualifiedName">FQN for the method/type under test</param>
        /// <param name="currentName">Name of current method/type </param>
        /// <returns>Number if violations</returns>
        private int ProcessMetrics(IBuildInformationNode parent, IEnumerable <Metric> metrics, SpecificMetricThresholds thresholds, string fullyQualifiedName, string currentName)
        {
            var thecomplainlist = new List <string>();

            foreach (var metric in metrics.Where(metric => metric != null && !string.IsNullOrEmpty(metric.Value)))
            {
                switch (metric.Name)
                {
                case MaintainabilityIndex:
                    this.CheckLimits(metric, thresholds.MIMetricChecker, fullyQualifiedName, thecomplainlist);
                    break;

                case CyclomaticComplexity:
                    this.CheckLimits(metric, thresholds.CCMetricChecker, fullyQualifiedName, thecomplainlist);
                    break;

                case ClassCoupling:
                    this.CheckLimits(metric, thresholds.COMetricChecker, fullyQualifiedName, thecomplainlist);
                    break;

                case DepthOfInheritance:
                    this.CheckLimits(metric, thresholds.DOIMetricChecker, fullyQualifiedName, thecomplainlist);
                    break;

                case LinesOfCode:
                    this.CheckLimits(metric, thresholds.LOCMetricChecker, fullyQualifiedName, thecomplainlist);
                    break;

                default:
                    throw new UnknownMetricNameException(metric.Name);
                }
            }

            if (this.logCodeMetrics && parent != null && thecomplainlist.Count > 0)
            {
                var result = "Metrics for " + currentName + @"\n";
                thecomplainlist.ForEach(s => result += s + @"\n");
                BaseCodeActivity.AddTextNode(result, parent);
            }

            return(thecomplainlist.Count);
        }
예제 #8
0
        static string ShowChild(IBuildInformationNode node, int level)
        {
            string levelStr = new string(' ', level * 4);
            foreach (var field in node.Fields)
            {
                if (field.Key == "ReservedAgentName")
                {
                    return field.Value;
                }
            }

            foreach (var child in node.Children.Nodes)
            {
                string AgentName = ShowChild(child, level + 1);
                if (!string.IsNullOrEmpty(AgentName))
                {
                    return AgentName;
                }
            }
            return string.Empty;
        }
예제 #9
0
        internal BuildDetailSectionStatus Initialize(IBuildDetail bd)
        {
            var result = new BuildDetailSectionStatus();

            bd.RefreshAllDetails();

            var workItemsOpened = new StringBuilder();
            List <IBuildInformationNode> workItemsOpenedNodes = bd.Information.GetNodesByType("OpenedWorkItem");

            workItemsOpenedNodes.ForEach(node =>
            {
                workItemsOpened.AppendFormat("{0} ({1}/{2}) ; ",
                                             node.Fields["WorkItemId"],
                                             node.Fields["Status"],
                                             node.Fields["AssignedTo"]);
            });

            List <IBuildInformationNode> steps = bd.Information.GetNodesByType("BuildStep");
            IBuildInformationNode        buildCompletedNode = steps.Find(node =>
            {
                return(node.Fields["Name"] == "BuildCompleted");
            });

            if (buildCompletedNode != null)
            {
                result.Success = (buildCompletedNode.Fields["Status"].ToLower() == "succeeded");
                result.Message = buildCompletedNode.Fields["Message"];
            }
            else
            {
                result.Success = false;
                result.Message = string.Empty;
            }


            // build name link label
            var control_BuildName = new LinkLabel();

            control_BuildName.BackColor = Color.Transparent;
            control_BuildName.Text      = bd.BuildNumber;
            control_BuildName.AutoSize  = true;
            control_BuildName.Tag       = bd.DropLocation;
            control_BuildName.Click    += BuildName_Click;

            // log file link label
            var control_Log = new LinkLabel();

            control_Log.BackColor = Color.Transparent;
            control_Log.Text      = bd.LogLocation;
            control_Log.AutoSize  = true;
            control_Log.Click    += LogFile_Click;

            var itemValues = new List <object>
            {
                control_BuildName, bd.RequestedBy, bd.BuildDefinition.TeamProject,
                bd.BuildDefinition.Name,
                string.Empty,                  //bd.BuildAgent.Name,
                string.Empty,                  //bd.CommandLineArguments,
                bd.StartTime.ToString(), bd.FinishTime.ToString(), bd.LastChangedBy,
                bd.LastChangedOn.ToString(), bd.Quality,
                workItemsOpened.ToString(), bd.SourceGetVersion, control_Log
            };

            this.lvItems.BeginUpdate();
            try
            {
                this.lvItems.Controls.Clear();
                this.table.Rows.Clear();
                for (int i = 0; i < this.itemNames.Length; i++)
                {
                    string itemName  = this.itemNames[i];
                    var    itemValue = (itemValues[i] is string?itemValues[i] : string.Empty) as string;

                    var newRow = new Row();
                    newRow.Cells.Add(new Cell(itemName));
                    var cell = new Cell(itemValue);
                    newRow.Cells.Add(cell);
                    this.table.Rows.Add(newRow);

                    if (itemValues[i] is Control)
                    {
                        Rectangle cellRect = this.lvItems.CellRect(cell);
                        var       control  = itemValues[i] as Control;
                        this.lvItems.Controls.Add(control);
                        control.Location = new Point(cellRect.X, cellRect.Y - 1);
                        control.BringToFront();
                    }
                }
            }
            finally
            {
                this.lvItems.EndUpdate();
                Rectangle rectangle = this.lvItems.ColumnRect(1);
                this.ValueColumnLeftPos = rectangle.Left + 14;
            }

            #region debug

            //                        Debug.WriteLine(new string('-', 120));
            //                        foreach (var node in bd.Information.Nodes)
            //                        {
            //                            Debug.WriteLine(string.Format("Type: {0}", node.Type));
            //                            foreach (var field in node.Fields)
            //                            {
            //                                Debug.WriteLine(string.Format("  Field: {0} | Value: {1}", field.Key, field.Value));
            //                            }
            //                            Debug.WriteLine(new string('=', 120));
            //                        }

            #endregion

            return(result);
        }
예제 #10
0
        /// <summary>
        /// Executes the logic for this workflow activity
        /// </summary>
        protected override void InternalExecute()
        {
            this.logCodeMetrics = this.LogCodeMetrics.Get(this.ActivityContext);
            this.BuildDetail    = this.ActivityContext.GetExtension <IBuildDetail>();
            string generatedFile = "Metrics.xml";

            string outputLocation = this.BuildDetail.DropLocation;

            if (string.IsNullOrEmpty(outputLocation))
            {
                outputLocation = this.BinariesDirectory.Get(this.ActivityContext);
            }

            if (this.GeneratedFileName != null && !string.IsNullOrEmpty(this.GeneratedFileName.Get(this.ActivityContext)))
            {
                generatedFile = Path.Combine(outputLocation, this.GeneratedFileName.Get(this.ActivityContext));
            }

            if (!this.RunCodeMetrics(generatedFile))
            {
                return;
            }

            IActivityTracking currentTracking = this.ActivityContext.GetExtension <IBuildLoggingExtension>().GetActivityTracking(this.ActivityContext);

            if (!this.AnalyzeMetricsResult.Get(this.ActivityContext))
            {
                BaseCodeActivity.AddTextNode("Skipped code metrics analysis (not set to run)", currentTracking.Node);
                return;
            }

            IBuildInformationNode rootNode = AddTextNode("Analyzing code metrics results", currentTracking.Node);

            string fileName = Path.GetFileName(generatedFile);
            string pathToFileInDropFolder = Path.Combine(outputLocation, fileName);

            BaseCodeActivity.AddLinkNode(fileName, new Uri(pathToFileInDropFolder), rootNode);

            CodeMetricsReport result = CodeMetricsReport.LoadFromFile(generatedFile);

            if (result == null)
            {
                this.LogBuildMessage("Could not load metric result file ");
                return;
            }

            // Get thresholds for each level.
            var memberMetricThresholds = new MethodMetricsThresholds(this);
            var typeMetricThresholds   = new TypeMetricsThresholds(this, memberMetricThresholds);

            // var namespaceMetricThresholds = new NameSpaceMetricsThresholds(this);  //Uncomment in this if you want to perform metric checks on namespaces
            // var assemblyMetricThresholds = new AssemblyMetricsThresholds(this);  // Uncomment in this if you want to perform metric checks on assemblies
            int noOfTypeViolations   = 0;
            int noOfMethodViolations = 0;

            foreach (var target in result.Targets)
            {
                var targetNode = this.logCodeMetrics ? AddTextNode("Target: " + target.Name, rootNode) : null;
                foreach (var module in target.Modules)
                {
                    var moduleNode = this.logCodeMetrics ? AddTextNode("Module: " + module.Name, targetNode) : null;

                    foreach (var ns in module.Namespaces)
                    {
                        var namespaceNode = this.logCodeMetrics ? AddTextNode("Namespace: " + ns.Name, moduleNode) : null;

                        foreach (var type in ns.Types)
                        {
                            var typeNode        = this.logCodeMetrics ? AddTextNode("Type: " + type.Name, namespaceNode) : null;
                            var typeInformation = new MemberInformation(null, type, ns, module);
                            noOfTypeViolations   += this.ProcessMetrics(typeNode, typeInformation.TheClass.Metrics, typeMetricThresholds, typeInformation.FullyQualifiedName, typeInformation.TheClass.Name);
                            noOfMethodViolations += (from member in type.Members let memberNode = this.logCodeMetrics ? AddTextNode("Member: " + member.Name + " " + member.MetricsInformation, typeNode) : null let memberInformation = new MemberInformation(member, type, ns, module) select this.ProcessMetrics(memberNode, memberInformation.TheMember.Metrics, memberMetricThresholds, memberInformation.FullyQualifiedName, memberInformation.TheMember.Name)).Sum();
                        }
                    }
                }
            }

            var numberMessageTypes   = string.Format("Number of Code Metric warnings/errors on types: {0}", noOfTypeViolations);
            var numberMessageMethods = string.Format("Number of Code Metric warnings/errors on methods: {0}", noOfMethodViolations);

            BaseCodeActivity.AddTextNode(numberMessageTypes, rootNode);
            BaseCodeActivity.AddTextNode(numberMessageMethods, rootNode);
        }
 /// <summary>
 /// Add a hyperlink to the
 /// </summary>
 /// <param name="text">Display text of the hyperlink</param>
 /// <param name="uri">Uri of the hyperlink</param>
 /// <param name="parent">Parent node in the build log</param>
 /// <returns>The new external link containing the supplied hyperlink</returns>
 protected static IExternalLink AddLinkNode(string text, Uri uri, IBuildInformationNode parent)
 {
     var link = parent.Children.AddExternalLink(text, uri);
     link.Save();
     return link;
 }
 /// <summary>
 /// Add a text node to the build log
 /// </summary>
 /// <param name="text">Display text</param>
 /// <param name="parent">Parent node in the build log</param>
 /// <returns>The new node containing the supplied text</returns>
 protected static IBuildInformationNode AddTextNode(string text, IBuildInformationNode parent)
 {
     IBuildInformationNode childNode = parent.Children.CreateNode();
     childNode.Type = parent.Type;
     childNode.Fields.Add("DisplayText", text);
     childNode.Save();
     return childNode;
 }
예제 #13
0
        /// <summary>
        /// Analyzes the resulting metrics file and compares the metrics against the threshold values
        /// </summary>
        /// <param name="parent">The parent node in the build log</param>
        /// <param name="metrics">List of metric values</param>
        /// <param name="thresholds">Thresholds for errors and warnings </param>
        /// <param name="fullyQualifiedName">FQN for the method/type under test</param>
        /// <param name="currentName">Name of current method/type </param>
        /// <returns>Number if violations</returns>
        private int ProcessMetrics(IBuildInformationNode parent, IEnumerable<Metric> metrics, SpecificMetricThresholds thresholds, string fullyQualifiedName, string currentName)
        {
            var thecomplainlist = new List<string>();
            foreach (var metric in metrics.Where(metric => metric != null && !string.IsNullOrEmpty(metric.Value)))
            {
                switch (metric.Name)
                {
                    case MaintainabilityIndex:
                        this.CheckLimits(metric, thresholds.MIMetricChecker, fullyQualifiedName, thecomplainlist);
                        break;
                    case CyclomaticComplexity:
                        this.CheckLimits(metric, thresholds.CCMetricChecker, fullyQualifiedName, thecomplainlist);
                        break;
                    case ClassCoupling:
                        this.CheckLimits(metric, thresholds.COMetricChecker, fullyQualifiedName, thecomplainlist);
                        break;
                    case DepthOfInheritance:
                        this.CheckLimits(metric, thresholds.DOIMetricChecker, fullyQualifiedName, thecomplainlist);
                        break;
                    case LinesOfCode:
                        this.CheckLimits(metric, thresholds.LOCMetricChecker, fullyQualifiedName, thecomplainlist);
                        break;
                    default:
                        throw new UnknownMetricNameException(metric.Name);
                }
            }

            if (this.logCodeMetrics && parent != null && thecomplainlist.Count > 0)
            {
                var result = "Metrics for " + currentName + @"\n";
                thecomplainlist.ForEach(s => result += s + @"\n");
                BaseCodeActivity.AddTextNode(result, parent);
            }

            return thecomplainlist.Count;
        }