Plugin to view All latest project statistics on a server.

[email protected] Fri, 30 Dec 2011 09:16:32 -0500
Newsgroups gmane.comp.java.cruise-control.devel
Message-ID <OFCF0534BD.66F3F9D0-ON85257976.004C5A05-85257976.004E6C10@bnymellon.com>
Contribution for CuriseControl.Net - A plugin to display last statistics 
for all Projects on a server with Project Statistics.

Configuration:

  <serverPlugins>
      <serverReportServerPlugin />
      <!-- Add your plugin here -->
      <serverStatisticsPlugin />
    </serverPlugins>

Link:  Server Statistics

Limits: 
        - All projects on that server have to have the same statistics 
columns configured.
        - Has not been tested on a server with no project statistics 
configured.
        - I am new to CruseControl.Net - suggestions are welcome.


---------- ServerStatistics.cs Plugin -----------
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Exortech.NetReflector;
using ThoughtWorks.CruiseControl.Core.Reporting.Dashboard.Navigation;
using ThoughtWorks.CruiseControl.Core.Util;
using ThoughtWorks.CruiseControl.Remote;
using ThoughtWorks.CruiseControl.WebDashboard.Dashboard;
using ThoughtWorks.CruiseControl.WebDashboard.IO;
using ThoughtWorks.CruiseControl.WebDashboard.MVC;
using ThoughtWorks.CruiseControl.WebDashboard.MVC.Cruise;
using ThoughtWorks.CruiseControl.WebDashboard.MVC.View;
using ThoughtWorks.CruiseControl.WebDashboard.Plugins.Statistics;
using ThoughtWorks.CruiseControl.WebDashboard.ServerConnection;


namespace ThoughtWorks.CruiseControl.WebDashboard.Plugins.ServerStatistics
{
    /// <summary>
    /// Purpose: 
    ///     Gives an overview of all projects statistics on this server.
    ///     Names the Link for the Server web site
    ///     Provides the Action Class that handles the request when 
requested
    /// 
    /// Important:  This plugin depends upon your configuring and using 
the 
    ///     ProjectStatisticsPlugin - since it uses the results.xml file
    ///     that it producedes.
    /// 
    ///     First configure ProjectStatisticsPlugin, then configure this 
plugin
    ///     to view all project statistics on the server.
    /// <para>
    /// LinkDescription : "Server Statistics".
    /// </para>
    /// </summary>
    /// <example>
    /// <code title="Minimalist example">
    /// &lt;serverStatisticsPlugin /&gt;
    /// </code>
    /// </example>
    /// <title>Server Statistics Plugin</title>
    /// <version>1.0.0</version>
    [ReflectorType("serverStatisticsPlugin")]
    public class ServerStatisticsPlugin : ICruiseAction, IPlugin
    {
        public static readonly string ACTION_NAME = 
"ViewServerStatisticsReport";
        private readonly IFarmService farmService;
        private readonly IVelocityViewGenerator viewGenerator;
        private readonly ICruiseUrlBuilder urlBuilder;

        #region Constructor

        // Constructor for use with built-in Action class
        public ServerStatisticsPlugin(IFarmService farmServer, 
IVelocityViewGenerator viewGenerator, ICruiseUrlBuilder urlBuilder)
        {
            this.farmService = farmServer;
            this.viewGenerator = viewGenerator;
            this.urlBuilder = urlBuilder;
        }

        #endregion


        #region IPlugin Members

        /// <summary>
        /// Provide the Menu Link that invokes FarmStatisticsAction
        /// </summary>
        public string LinkDescription
        {
            get { return "Server Statistics"; }
        }

        public INamedAction[] NamedActions
        {
            get { return new INamedAction[] { new ImmutableNamedAction(
"ViewServerStatistics", this) }; }
        }

        #endregion


        #region ICruiseAction Members

        /// <summary>
        /// Execute this action after a user clicks the "Server 
Statistics" link, 
        /// to show all projects latest statistics (configured through the 

        /// ProjectStatistics Plugin).
        /// </summary>
        /// <param name="request">CruiseControl web request</param>
        /// <returns>IResponse page to the web server</returns>
        public IResponse Execute(ICruiseRequest request)
        {
            IProjectSpecifier project;
            string statisticsDocument;
            Hashtable velocityContext = new Hashtable();
 
            CruiseServerSnapshotListAndExceptions snapshot = 
farmService.GetCruiseServerSnapshotListAndExceptions(request.ServerSpecifier, 
request.RetrieveSessionToken());
            List<QueueSnapshot> queues = new List<QueueSnapshot>();
            ArrayList statisticsList;
            List<ArrayList> projectStatisticsList = new List<ArrayList>();

            for (int idxSnapshot = 0; idxSnapshot < 
snapshot.Snapshots.Length; idxSnapshot++)
            {
                QueueSetSnapshot queueSnapshot = 
snapshot.Snapshots[idxSnapshot].QueueSetSnapshot;
                for (int idxQueue = 0; idxQueue < 
queueSnapshot.Queues.Count; idxQueue++)
                {
                    queues.Add(queueSnapshot.Queues[idxQueue]);
                    project = GetProjectSpecifier(request, 
queueSnapshot.Queues[idxQueue].QueueName);
 
                    // Use the ProjectStatisticsPlugin results xml file.
                    statisticsDocument = 
farmService.GetStatisticsDocument(project, 
request.RetrieveSessionToken());
                    Log.Debug(statisticsDocument);

                    try
                    {

                        // Read the ProjectStatisticsPlugin results xml 
file
                        statisticsList = GetEachProjectStatistics(project, 
statisticsDocument);

                        if (statisticsList.Count > 2)  // Name, and Status 
are expected
                        {
                            // Add for single project statisticsList of 
Colums
                            // Columns are in Name-Value pairs
                            projectStatisticsList.Add(statisticsList);
                        }
                    }
                    catch (XmlException)
                    {
                        // The Project does not have Statistics configured 
or gathered.
                        // Nothing to do since not all projects have 
Statistics.
                        //"Missing/Invalid statistics reports. Please 
check if you have enabled the Statistics Publisher, and statistics have 
been collected atleast once after that.";
                    }
                }
            }

            // Data for table of Project Statistics
            velocityContext["projectStatisticsList"] = 
projectStatisticsList;

            return viewGenerator.GenerateView(@"ServerStatistics.vm", 
velocityContext);
        }

        #endregion


        #region Helper Methods

        /// <summary>
        /// Get the Project Specifier given the project name
        /// Prerequisite:  Select a server so request will have the server 
name
        /// </summary>
        /// <param name="request">ICruiseRequest web request information
</param>
        /// <returns>DefaultProjectSpecifier</returns>
        private IProjectSpecifier GetProjectSpecifier(ICruiseRequest 
request, string projectName)
        {
            string server = request.ServerName;
            return new DefaultProjectSpecifier
(farmService.GetServerConfiguration(server), projectName);
        }

// Example:
//</statistics>
//  <integration build-label="3" status="Success" day="22" month="Dec" 
year="2011">
//    <statistic name="StartTime">2011-12-22 10:12:55</statistic> 
//    <statistic name="Duration">00:00:49</statistic> 
//    <statistic name="TestCount">4</statistic> 
//    <statistic name="TestFailures">0</statistic> 
//    <statistic name="TestIgnored">0</statistic> 
//    <statistic name="BuildErrorType" /> 
//    <statistic name="BuildErrorMessage" /> 
//  </integration>
//  <timestamp day="22" month="Dec" year="2011" /> 
//</statistics>

        /// <summary>
        /// Read a project statistics xml report, parse, and 
        /// get an ordered list of project statistics data in Name-Value 
pairs/
        /// </summary>
        /// <param name="project">Project specifier</param>
        /// <param name="statisticsDocument">Project Statistics XML string
</param>
        /// <returns>ordered list of project statistics data in Name-Value 
pairs</returns>
        /// <remarks>Uses an XmlDocument</remarks>
        private ArrayList GetEachProjectStatistics(IProjectSpecifier 
project, string statisticsDocument)
        {
            // Read the ProjectStatisticsPlugin results xml file
            // to duplicate the column names configured for that plugin
            // also read the values from the xml file produced by 
ProjectStatisticsPlugin
            ArrayList statisticsList = new ArrayList();
            XmlDocument doc = new XmlDocument();
            string href;

            using (XmlReader reader = XmlReader.Create(new StringReader
(statisticsDocument)))
            {
                    doc.Load(reader);
                    //XPathNavigator nav = doc.CreateNavigator();
                    XmlNode root = doc.DocumentElement;
                    XmlNodeList integrationNodes = root.SelectNodes(
@"integration");
                    XmlNode current = null;

                    if ((integrationNodes != null) && 
(integrationNodes.Count > 0))
                    {
                        // Use last integration node
                        current = integrationNodes[integrationNodes.Count 
- 1];

                        // First Column
                        Hashtable Col1 = new Hashtable();
                        // Add a Project Statistics URL
                        href = @"<a href=" + urlBuilder.BuildProjectUrl(
ProjectStatisticsPlugin.ACTION_NAME, project) + ">" + project.ProjectName 
+ "</a>";
                        Col1.Add(@"Name", href);
                        statisticsList.Add(Col1);

                        if (current.Attributes.Count >= 2)
                        {
                            // Second Status Attribute
                            string status = current.Attributes[1].Value;
                            Hashtable Col2 = new Hashtable();
                            Col1.Add(@"Status", status);
                            statisticsList.Add(Col2);
                        }

                        // move to the "statistic" nodes
                        XmlNodeList statisticsNodes = current.SelectNodes(
@"statistic");
                        Hashtable Coln; // project statistics columns(n)

                        foreach (XmlNode node in statisticsNodes)
                        {
                            Coln = new Hashtable();
                            if (node.Attributes.Count > 0)
                            {
                                string name = node.Attributes[0].Value;
                                string value = node.InnerText;
                                Coln.Add(name, value);
                                statisticsList.Add(Coln);
                            }
                        }
                    }
            }
            return statisticsList;
        }

        /// <summary>
        /// Read a project statistics xml report, parse, and 
        /// get an ordered list of project statistics data in Name-Value 
pairs/
        /// </summary>
        /// <param name="project">Project specifier</param>
        /// <param name="statisticsDocument">Project Statistics XML string
</param>
        /// <returns>ordered list of project statistics data in Name-Value 
pairs</returns>
        /// <remarks>Uses an XmlReader</remarks>
        private ArrayList GetProjectStatistics(IProjectSpecifier project, 
string statisticsDocument)
        {
            // Read the ProjectStatisticsPlugin results xml file
            // to duplicate the column names configured for that plugin
            // also read the values from the xml file produced by 
ProjectStatisticsPlugin
            ArrayList statisticsList = new ArrayList();
            using (XmlReader reader = XmlReader.Create(new StringReader
(statisticsDocument)))
            {
                reader.ReadToFollowing("integration");
                reader.MoveToFirstAttribute();
                string buildLabel = reader.Value;

                Hashtable Col0 = new Hashtable();
                Col0.Add("Name", project.ProjectName);

                // Wait to see if we can read this project statistics
                // If we can then start a statisticsList of columns
                // for this project.
                statisticsList.Add(Col0);

                reader.MoveToNextAttribute();
                string status = reader.Value;
                Hashtable Col1 = new Hashtable();
                Col1.Add("Status", status);
                statisticsList.Add(Col1);

                Hashtable Coln; // project status column n

                while (reader.Read())
                {
                    reader.ReadToFollowing("statistic");
                    string value = reader.Value;
                    reader.MoveToFirstAttribute();
                    string name = reader.Value;

                    // Read the rest of the configured columns
                    Coln = new Hashtable();
                    Coln.Add(name, value);
                    statisticsList.Add(Coln);
                }
            }
            return statisticsList;
        }

        #endregion

    }
}
-------------------------

---------  ServerStatistics.vm Template ---------
<!-- ServerStatistics.vm: Start -->
<script type="text/javascript">
  $(document).ready(function(){
  $('#ServerStatistics').tablesorter({
  sortList:[[0,0]]
  });
  });
</script>
<table class="SortableGrid" id="ServerStatistics">
  <thead>
    <tr class="ProjectGridHeader">
##
## Note: Process each project statistics row for the Table Header
##
#foreach ($statisticsList in $projectStatisticsList)
#if ( $velocityCount == 1 )
#foreach ($col in $statisticsList)
  #foreach ($key in $col.Keys)<th>$key</th>#end
#end
#end
#end
    </tr>
  </thead>
  <tbody>
##
## Note: Process each project statistics row for the Table Data
##
#foreach ($statisticsList in $projectStatisticsList)
    <tr>
#foreach ($col in $statisticsList)
#foreach ($value in $col.Values)
#if ($value == "Success")
<td class="Green">$value</td>
#elseif ($value == "Failure")
<td class="Red">$value</td>
#else
<td>$value</td>
#end
#end
#end
    </tr>
#end
  </tbody>
</table>
<!-- ServerStatistics.vm: End -->
---------------------------------------------



Thanks,
Stephen


The information contained in this e-mail, and any attachment, is confidential and is intended solely for the use of the intended recipient. Access, copying or re-use of the e-mail or any attachment, or any information contained therein, by any other person is not authorized. If you are not the intended recipient please return the e-mail to the sender and delete it from your computer. Although we attempt to sweep e-mail and attachments for viruses, we do not guarantee that either are virus-free and accept no liability for any damage sustained as a result of viruses. 

Please refer to http://disclaimer.bnymellon.com/eu.htm for certain disclosures relating to European legal entities.

------------------------------------------------------------------------------
Ridiculously easy VDI. With Citrix VDI-in-a-Box, you don't need a complex
infrastructure or vast IT resources to deliver seamless, secure access to
virtual desktops. With this all-in-one solution, easily deploy virtual 
desktops for less than the cost of PCs and save 60% on VDI infrastructure 
costs. Try it free! http://p.sf.net/sfu/Citrix-VDIinabox

_______________________________________________
Cruisecontrol-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/cruisecontrol-devel
(unnamed) (image/gif, 19.7 KB) - not displayed