package com.coverity.ps.integrations.reporting; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import com.coverity.ps.common.CimProxy; import com.coverity.ws.v4.CovRemoteServiceException_Exception; import com.coverity.ws.v4.MergedDefectDataObj; import com.coverity.ws.v4.MergedDefectFilterSpecDataObj; import com.coverity.ws.v4.ProjectDataObj; /** * Creates a summary e-mail report of defects that have been detected in the * last N number of days based upon component. */ public class NotifyComponentManagers { private String projectName; private int days; private List<String> users = new ArrayList<String>(); private boolean isDryRun; /** * Constructor * * @param project * project name * @param days * defects detected in the past N number of days * @param isDryRun */ public NotifyComponentManagers(String projectName, int days, String managerList, boolean isDryRun) { this.projectName = projectName; this.days = days; this. isDryRun = isDryRun; // get list of user to e-mail String[] managers = managerList.split(","); for(String manager : managers) { this.users.add(manager); } } private List<MergedDefectDataObj> getProjectDefects() throws CovRemoteServiceException_Exception, DatatypeConfigurationException { // get project id ProjectDataObj projectData = CimProxy.getInstance().getProject( projectName); if (projectData != null) { // calculate as-of date final long oneDay = 1000 * 60 * 60 * 24; GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeInMillis(System.currentTimeMillis() - this.days * oneDay); XMLGregorianCalendar lastDetected = DatatypeFactory.newInstance() .newXMLGregorianCalendar(calendar); System.out.println("as-of-date=" + lastDetected); // get defects MergedDefectFilterSpecDataObj projectFilter = new MergedDefectFilterSpecDataObj(); projectFilter.setFirstDetectedStartDate(lastDetected); return CimProxy.getInstance().getMergedDefectsForProject( this.projectName, projectFilter); } return null; } public boolean execute() throws Exception { List<MergedDefectDataObj> componentDefects = getProjectDefects(); if (componentDefects != null) { StringBuilder html = new StringBuilder(); html.append("<html><body><p>The following defects have been detected in the "); html.append(this.projectName); html.append(" project within the past "); if (days == 1) { html.append("24 hours.</p>"); } else { html.append(days + " days.</p>"); } Map<String, List<MergedDefectDataObj>> defectsByChecker = new HashMap<String, List<MergedDefectDataObj>>(); for (MergedDefectDataObj componentDefect : componentDefects) { // System.out.println("cid=" + componentDefect.getCid() + // ", component=" + componentName); List<MergedDefectDataObj> checkerDefects = (List<MergedDefectDataObj>) defectsByChecker .get(componentDefect.getCheckerName()); if (checkerDefects == null) { checkerDefects = new ArrayList<MergedDefectDataObj>(); defectsByChecker.put(componentDefect.getCheckerName(), checkerDefects); } checkerDefects.add(componentDefect); } // process checker information for current component html.append("<style type='text/css'>"); html.append("td.datacellone {"); html.append(" background-color: #F2F2F2; color: black;"); html.append("}"); html.append("td.datacelltwo {"); html.append(" background-color: #FFFFFF; color: black;"); html.append("}"); html.append("td.datacellthree {"); html.append(" background-color: #BDBDBD; color: black;"); html.append("}"); html.append("</style>"); html.append("<br/><table border=\"1\" cellpadding=\"3\"><tr> <th>Checker</th> <th>New</th> <th>Outstanding</th> <th>Resolved</th> <th>Total</th></tr>"); // column totals int totalNew = 0; int totalTriaged = 0; int totalResolved = 0; int totalTotal = 0; int i = 0; for (Map.Entry<String, List<MergedDefectDataObj>> checkerDefectEntries : defectsByChecker .entrySet()) { List<MergedDefectDataObj> checkerDefects = checkerDefectEntries .getValue(); final String checkerName = (String) checkerDefectEntries .getKey(); int checkerNew = 0; int checkerTriaged = 0; int checkerResolved = 0; for (MergedDefectDataObj checkerDefect : checkerDefects) { // new if (checkerDefect.getStatus().equals("New")) { checkerNew++; } // outstanding else if (checkerDefect.getStatus().equals("Triaged")) { checkerTriaged++; } // resolved: note assume dismissed and fixed else if (checkerDefect.getStatus().equals("Dismissed") || checkerDefect.getStatus().equals("Fixed")) { checkerResolved++; } } /* * System.out.println("\tchecker=" + checkerName + ", new=" + * checkerNew + ", outstanding=" + checkerOutstanding + * ", resolved=" + checkerResolved); */ String td; if (i % 2 == 0) { td = "<td class='datacellone'>"; } else { td = "<td class='datacelltwo'>"; } html.append("<tr>"); html.append(td); html.append(checkerName); html.append("</td>"); html.append(td); html.append(checkerNew); html.append("</td>"); html.append(td); html.append(checkerTriaged); html.append("</td>"); html.append(td); html.append(checkerResolved); html.append("</td>"); html.append(td); html.append(checkerDefects.size()); html.append("</td></tr>"); // update totalNew += checkerNew; totalTriaged += checkerTriaged; totalResolved += checkerResolved; totalTotal += checkerDefects.size(); i++; } // totals String td = "<td class='datacellthree'>"; html.append("<tr>"); html.append(td); html.append("Total</td>"); html.append(td); html.append(totalNew); html.append("</td>"); html.append(td); html.append(totalTriaged); html.append("</td>"); html.append(td); html.append(totalResolved); html.append("</td>"); html.append(td); html.append(totalTotal); html.append("</td></tr>"); html.append("</table></body></html>"); System.out.println("Raw HTML=" + html); // e-mail to component owners if(this.isDryRun) { System.out.println("Recipients that would have received e-mail(s): " + this.users); } else { final String subject = "New Coverity defects"; List<String> recipients = CimProxy.getInstance().notify(this.users, subject, html.toString()); for(String recipient : recipients) { System.out.println("e-mail sucessfully sent to " + recipient); } } } return true; } /* * Main command line driver. Please see class constructor for required * arguments. */ public static void main(String[] args) { try { if (args.length == 4) { NotifyComponentManagers notifyOwners = new NotifyComponentManagers( args[0], Integer.parseInt(args[1]), args[2], args[3].equalsIgnoreCase("true")); if (notifyOwners.execute()) { System.out.println("\nSuccessful!"); } else { System.out.println("\n*** Unsuccessful ***"); } } else { System.err .println("This program notifies component owners of new defects that have been detected in the last N number of days."); System.err .println("usage: java " + NotifyComponentManagers.class.getName() + " <project-name> <num-days> <users-to-email> <is-dry-run>"); } } catch (Exception e) { e.printStackTrace(); } } }