/* * aegis - project change supervisor * Copyright (C) 1997, 1998, 2001-2003, 2005-2008 Peter Miller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ auto pn; pn = project_name(); auto script_name; script_name = getenv("SCRIPT_NAME"); if (script_name == "") script_name = "http://localhost/cgi-bin/aegis.cgi"; columns({width = 1000; }); print("Content-Type: text/html"); print(""); print(""); print(""); print(""); print(""); print(""); print(""); /* * Netscape 4.x has numerous CSS bugs, two of which need mentioning. * 1. If a style sheet is not present Netscape says 404 Not found, when * it should silently ignore it. 2. Style sheets who's media is not * "screen" will be ignored. Fortunately we can use (2) to get around (1). */ print(""); auto stack, depth, n; depth=0; stack[depth] = project[pn].state.name; while ("" != ( n = project[stack[depth]].state.parent_name )) { stack[++depth] = n; } while ( depth >= 0) { print(""); } print(""); print("Project " ## quote_html(pn) ## " Statistics"); print("

"); auto href; print("Project"); auto long_project_name; auto prj_name_parts; prj_name_parts = split(pn, '.'); href = script_name ## "?file@proj_menu+project@" ## quote_url(prj_name_parts[0]); long_project_name = "" ## quote_html(prj_name_parts[0]) ## ""; auto j; for (j = 1; j < count(prj_name_parts); j++) { href ##= '.' ## prj_name_parts[j]; long_project_name ##= "." ## quote_html(prj_name_parts[j]) ## ""; }; long_project_name = "“" ## long_project_name ## "”,
"; /* HTTP limits lines to 510 characters */ for (j in wrap(long_project_name, 510)) print(j); print("Statistics"); print("

"); print("
"); print("This page provides a number of statistical projections of the"); print("audit data collected as changes progress through the development"); print("process."); auto p, ps; p = project[pn]; ps = p.state.branch; /* * traverse each change */ auto cause_stats, cause_total; auto file_action_stats, file_action_total; auto file_usage_stats, file_usage_total; auto hist_now, hist_time, hist_state, hist_stats, hist_total; auto hist_total_min, hist_total_max; auto hist_chan, hist_min, hist_max; hist_now = now(); auto cn, cs, idx; hist_min = { garbage = 0; }; hist_max = { garbage = 0; }; for (cn in keys(ps.change)) { cs = ps.change[cn]; cause_stats[cs.cause]++; cause_total++; for (idx in cs.src) { file_action_stats[idx.action]++; file_action_total++; if (idx.usage != build || idx.action != modify) { file_usage_stats[idx.usage]++; file_usage_total++; } } cs.history ##= [{ when = hist_now; what = integrate_pass; }]; hist_chan = { garbage = 0; }; for (idx in cs.history) { if (idx.what == new_change) { hist_time = idx.when; hist_state = awaiting_development; continue; } hist_chan[hist_state] += working_days(hist_time, idx.when); hist_time = idx.when; if (idx.what == new_change) hist_state = awaiting_development; else if (idx.what == develop_begin) hist_state = being_developed; else if (idx.what == develop_begin_undo) hist_state = awaiting_development; else if (idx.what == develop_end) hist_state = being_reviewed; else if (idx.what == develop_end_2ar) hist_state = awaiting_review; else if (idx.what == develop_end_2ai) hist_state = awaiting_integration; else if (idx.what == develop_end_undo) hist_state = being_developed; else if (idx.what == review_begin) hist_state = being_reviewed; else if (idx.what == review_begin_undo) hist_state = awaiting_review; else if (idx.what == review_fail) hist_state = being_developed; else if (idx.what == review_pass) hist_state = awaiting_integration; else if (idx.what == review_pass_undo) hist_state = being_reviewed; else if (idx.what == integrate_begin) hist_state = being_integrated; else if (idx.what == integrate_begin_undo) hist_state = awaiting_integration; else if (idx.what == integrate_fail) hist_state = being_developed; else break; } for (idx in [awaiting_development, being_developed, awaiting_review, being_reviewed, awaiting_integration, being_integrated]) { j = hist_chan[idx]; hist_stats[idx] += j; if (!hist_min[idx] || j < hist_min[idx]) hist_min[idx] = j; if (j > hist_max[idx]) hist_max[idx] = j; } j = working_days(cs.history[0].when, hist_time); hist_total += j; if (!hist_total_min || j < hist_total_min) hist_total_min = j; if (j > hist_total_max) hist_total_max = j; } /* * print statistics about change state durations */ print("
"); print("

Change Duration By State

"); print(""); print(""); print(""); for (idx in [awaiting_development, being_developed, awaiting_review, being_reviewed, awaiting_integration, being_integrated]) { hist_time = hist_stats[idx]; print(""); } print(""); print(""); print("
Change StateWorking DaysMinimumAverageMaximum
"); print(idx); print(""); print(sprintf("%.2f", hist_time)); print(""); print(sprintf("%.2f", hist_min[idx])); print(""); print(sprintf("%.2f", hist_time * 1. / cause_total)); print(""); print(sprintf("%.2f", hist_max[idx])); print("




Total"); print(""); print(sprintf("%.2f", hist_total)); print(""); print(sprintf("%.2f", hist_total_min)); print(""); print(sprintf("%.2f", hist_total * 1. / cause_total)); print(""); print(sprintf("%.2f", hist_total_max)); print("
"); /* * print statistics about change causes */ print("
"); print("

Change Cause Distribution

"); print(""); print(""); for (idx in sort(keys(cause_stats))) { print(""); } print(""); print(""); print("
Change CauseCountPercent
"); print(idx); print(""); print(cause_stats[idx]); print(""); print(sprintf("%.2f%%", 100. * cause_stats[idx] / cause_total)); print("

Total"); print(""); print(cause_total); print(""); print("
"); /* * print statistics about file actions */ print("
"); print("

Change File Action Distribution

"); print(""); print(""); print(""); for (idx in sort(keys(file_action_stats))) { print(""); } print(""); print(""); print("
ActionCountPercentAverage
"); print(idx); print(""); print(file_action_stats[idx]); print(""); print(sprintf("%.2f%%", 100. * file_action_stats[idx] / file_action_total)); print(""); print(sprintf("%.2f", file_action_stats[idx] * 1. / cause_total)); print("


Total"); print(""); print(file_action_total), print(""); print(sprintf("%.2f", file_action_total * 1. / cause_total)); print("
"); /* * print statistics about file usages */ print("
"); print("

Change File Type Distribution

"); print(""); print(""); for (idx in sort(keys(file_usage_stats))) { print(""); } print(""); print(""); print("
TypeCountPercentAverage
"); print(idx); print(""); print(file_usage_stats[idx]); print(""); print(sprintf("%.2f%%", 100. * file_usage_stats[idx] / file_usage_total)); print(""); print(sprintf("%.2f", file_usage_stats[idx] * 1. / cause_total)); print("


Total"); print(""); print(file_usage_total); print(""); print(sprintf("%.2f", file_usage_total * 1. / cause_total)); print("
"); print("
"); print("
"); print("
"); print("A similar report may be obtained from the command line, with"); print("
aer proj_stats -p " ## pn ## "
"); print("
"); print("
"); print("

["); print("Project List |"); href = script_name ## "?file@proj_menu+project@" ## quote_url(pn); print("Project Menu"); print("]

"); print("
"); print("This page was generated " ## now() ## "."); print("");