| <?php |
| |
| /** |
| * Copyright (c) 2018 Eclipse Foundation and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| */ |
| require_once dirname ( __FILE__ ) . '/Project.class.php'; |
| require_once dirname ( __FILE__ ) . '/common.php'; |
| require_once dirname ( __FILE__ ) . '/debug.php'; |
| |
| /** |
| * The ProjectStatusReporter class provides behaviour to load |
| * information about some subset of the projects, and then |
| * extract and provide that information in various ways. |
| * Several "columns" are defined, each of which knows how |
| * to extract and present some piece of the data. |
| * |
| */ |
| class ProjectStatusReporter { |
| var $columnDefintions; |
| var $projects; |
| function __construct($ids) { |
| $this->projects = self::loadProjects ( $ids ); |
| $this->columnDefinitions = array ( |
| 'name' => array ( |
| 'label' => 'Project Name' |
| ), |
| 'id' => array ( |
| 'label' => 'Project Id', |
| 'function' => function ($value, $key, $project) { |
| $link = $project ['url']; |
| return "<a href=\"$link\">$value</a>"; |
| } |
| ), |
| 'top' => array ( |
| 'label' => 'Top-Level' |
| ), |
| 'phase' => array ( |
| 'label' => 'Phase', |
| 'function' => function ($value, $key, $project) { |
| global $images; |
| return $value == 'incubating' ? "<img src=\"$images->incubation_conforming_small\"/>" : ' '; |
| } |
| ), |
| // 'liveliness' => array ( |
| // 'label' => 'Liveliness', |
| // 'function' => function ($value, $key, $project) { |
| // $liveliness = self::getLivelinessIcon ( $value ); |
| // return "<img src=\"$liveliness\"/>"; |
| // } |
| // ), |
| 'committers' => array ( |
| 'label' => 'Committers Count' |
| ), |
| 'organizations' => array ( |
| 'label' => 'Orgs Count' |
| ), |
| 'initial_cq' => array ( |
| 'label' => 'Initial Contribution', |
| 'function' => function ($value, $key, $project) { |
| if (! isset ( $value )) |
| return " "; |
| return "<a href=\"$value\"><img src=\"/projects/images/external.gif\"/></a>"; |
| } |
| ), |
| 'initial_cq_created' => array ( |
| 'label' => 'Initial Contribution Created' |
| ), |
| 'initial_cq_pmc' => array ( |
| 'label' => 'Initial Contribution PMC Approved' |
| ), |
| 'initial_cq_checkin' => array ( |
| 'label' => 'Initial Contribution Check-in' |
| ), |
| 'initial_cq_approved' => array ( |
| 'label' => 'Initial Contribution Approved' |
| ), |
| 'initial_cq_latency' => array ( |
| 'label' => 'Time Since IC Change', |
| 'function' => function ($value, $key, $project) { |
| if (@$project ['initial_cq_approved']) |
| return '--'; |
| if ($checkin = @$project ['initial_cq_checkin']) |
| return self::getTimeSince ( $checkin ); |
| if ($created = @$project ['initial_cq_created']) |
| return self::getTimeSince ( $created ); |
| return '--'; |
| }, |
| 'sort' => function ($value, $key, $project) { |
| if (@$project ['initial_cq_approved']) |
| return 0; |
| if ($checkin = @$project ['initial_cq_checkin']) |
| return ( int ) (time () - strtotime ( $checkin )); |
| if ($created = @$project ['initial_cq_created']) |
| return ( int ) (time () - strtotime ( $created )); |
| return 0; |
| }, |
| 'class' => 'column-align-right' |
| ), |
| 'commits_initial' => array ( |
| 'label' => 'Initial Commit' |
| ), |
| 'commits_latest' => array ( |
| 'label' => 'Latest Commit' |
| ), |
| 'commits' => array ( |
| 'label' => 'Commits Count', |
| 'function' => function ($value, $key, $project) { |
| if ($value !== null) |
| return number_format ( $value ); |
| return '--'; |
| }, |
| 'sort' => function ($value, $key, $project) { |
| return ( int ) $value; |
| }, |
| 'class' => 'column-align-right' |
| ), |
| 'commits_latency' => array ( |
| 'label' => 'Time Since Last Commit', |
| 'function' => function ($value, $key, $project) { |
| if ($latest = @$project ['commits_latest']) |
| return self::getTimeSince ( $latest ); |
| return '--'; |
| }, |
| 'sort' => function ($value, $key, $project) { |
| if ($latest = @$project ['commits_latest']) |
| return ( int ) (time () - strtotime ( $latest )); |
| return 0; |
| }, |
| 'class' => 'column-align-right' |
| ), |
| 'downloads_first' => array ( |
| 'label' => 'Oldest Download' |
| ) |
| ); |
| } |
| function values($id, $function) { |
| if ($project = $this->projects[$id]) { |
| foreach ( $this->columnDefinitions as $id => $config ) { |
| $function ( new ProjectStatusReporterColumn ( $id, $config, $project ) ); |
| } |
| } |
| } |
| public function getColumnDefinition($key) { |
| return $this->columnDefinitions [$key]; |
| } |
| public static function getTimeSince($date) { |
| if (! $date) |
| return 0; |
| $milliseconds = date ( time () - strtotime ( $date ) ); |
| $days = number_format ( ceil ( $milliseconds / (60 * 60 * 24) ) ); |
| return "$days days"; |
| } |
| public function filter($info) { |
| foreach ( $_GET as $key => $value ) { |
| if (isset ( $info [$key] )) { |
| if ($info [$key] != $value) |
| return true; |
| } |
| } |
| return false; |
| } |
| private static function loadProjects($ids) { |
| $projects = array (); |
| |
| foreach ( Project::getAllProjects ( $ids ) as $project ) { |
| switch ($id = $project->getId ()) { |
| case 'polarsys' : |
| break; |
| default : |
| $projects[$id] = array ( |
| 'project' => $project, |
| 'id' => $id, |
| 'name' => $project->getName (), |
| 'top' => $project->getTopLevelProject ()->getId (), |
| 'topName' => preg_replace ( '/ Root$/', '', $project->getTopLevelProject ()->getName () ), |
| 'phase' => $project->isInIncubationPhase () ? 'incubating' : 'regular', |
| 'url' => $project->getUrl (), |
| 'liveliness' => $project->getLiveliness () |
| ); |
| } |
| } |
| |
| self::addDashData ( $projects ); |
| self::addInitialContributionStats ( $projects ); |
| |
| return $projects; |
| } |
| |
| /** |
| * Add stats that are tracked by Dash. |
| * This generally refers to values |
| * that are calculated in batch and cached on the dashboard database. |
| * |
| * @param mixed $projects |
| */ |
| private static function addDashData(&$projects) { |
| $ids = self::getProjectIds ( $projects ); |
| $sql = " |
| select distinct |
| p.subproject as id, |
| date(ps.initialCommit) as commits_initial, |
| date(ps.latestCommit) as commits_latest, |
| ps.totalCommits as commits, |
| count(distinct pca.company) as organizations, |
| count(distinct pda.login) as committers, |
| min(pd.first) as downloads_first |
| from ProjectRollup as p |
| left join ProjectCompanyActivity as pca on p.subproject=pca.project |
| left join ProjectCommitterActivity as pda on p.subproject=pda.project |
| left join ProjectStats as ps on p.subproject=ps.project |
| left join ProjectInfoDownloads as pd on p.subproject=pd.project |
| where p.subproject in ($ids) |
| group by p.subproject"; |
| |
| query ( 'dashboard', $sql, array(), function ($row) use (&$projects) { |
| $id = $row ['id']; |
| if (isset ( $projects [$id] )) { |
| $projects [$id] += $row; |
| } |
| } ); |
| } |
| |
| /** |
| * This function answers a string containing the quoted ids for |
| * the projects. |
| * |
| * @param mixed $projects |
| * @return string |
| */ |
| private static function getProjectIds(&$projects) { |
| $ids = array (); |
| foreach ( $projects as $project ) { |
| $ids [] = "'{$project['id']}'"; |
| } |
| return implode ( ',', $ids ); |
| } |
| |
| /** |
| * Add information about the initial contribution to the |
| * project data. |
| * Note that data is only provided for projects |
| * that are already represented in the array. |
| * |
| * @param mixed $projects |
| */ |
| private static function addInitialContributionStats(&$projects) { |
| $ids = self::getProjectIds ( $projects ); |
| |
| $sql = "select |
| f.name as id, |
| b.bug_id as cq, |
| b.short_desc as title, |
| date(b.creation_ts) as created, |
| max(date(pmc.bug_when)) as pmc, |
| max(date(checkin.bug_when)) as checkin, |
| max(date(approved.bug_when)) as approved |
| from bugs as b |
| join (select |
| c.name, |
| min(bb.bug_id) as cq |
| from bugs as bb |
| join products as p on bb.product_id = p.id |
| join components as c on bb.component_id = c.id |
| join keywords as k on bb.bug_id=k.bug_id |
| join keyworddefs as kd on k.keywordid=kd.id and kd.name in ('projectcode') |
| where c.name in ($ids) |
| and c.name not in ('foundation-internal', 'IP_Discussion', 'IP', 'dsdp') |
| and bug_severity not in ('withdrawn') |
| and resolution not in ('INVALID') |
| group by c.id) as f on b.bug_id=f.cq |
| left join bugs_activity as pmc on b.bug_id=pmc.bug_id and pmc.added in ('PMC_Approved+') |
| left join bugs_activity as checkin on b.bug_id=checkin.bug_id and checkin.added in ('checkin', 'checkintocvs') |
| left join bugs_activity as approved on b.bug_id=approved.bug_id and approved.added in ('approved', 'approved_all_projects', 'FIXED', 'WORKSFORME') |
| group by f.name |
| order by f.name"; |
| |
| query ( 'ipzilla', $sql, array(), function ($row) use (&$projects) { |
| $id = $row ['id']; |
| if (isset ( $projects [$id] )) { |
| $cq = $row ['cq']; |
| $projects [$id] ['initial_cq'] = "https://dev.eclipse.org/ipzilla/show_bug.cgi?id=$cq"; |
| $projects [$id] ['initial_cq_created'] = $row ['created']; |
| $projects [$id] ['initial_cq_pmc'] = $row ['pmc']; |
| $projects [$id] ['initial_cq_checkin'] = $row ['checkin']; |
| $projects [$id] ['initial_cq_approved'] = $row ['approved']; |
| } |
| } ); |
| } |
| public static function valueOrDashes($value) { |
| if (! $value) |
| return '--'; |
| return $value; |
| } |
| function getLivelinessIcon($liveliness) { |
| global $images; |
| switch ($liveliness) { |
| case PROJECT_LIVELINESS_NEVER_ACTIVE : |
| return $images->tools_small; |
| case PROJECT_LIVELINESS_ACTIVE : |
| return $images->active_small; |
| case PROJECT_LIVELINESS_STALE : |
| return $images->stale_small; |
| case PROJECT_LIVELINESS_INACTIVE : |
| return $images->inactive_small; |
| case PROJECT_LIVELINESS_DEAD : |
| return $images->dead_small; |
| } |
| } |
| } |
| class ProjectStatusReporterColumn { |
| var $id, $config, $data; |
| public function __construct($id, $config, $data) { |
| $this->id = $id; |
| $this->config = $config; |
| $this->data = $data; |
| } |
| public function getTitle() { |
| return $this->config ['label']; |
| } |
| public function getValue() { |
| $value = $this->data [$this->id]; |
| if (isset ( $this->config ['function'] )) { |
| $function = $this->config ['function']; |
| $value = call_user_func($function, $value, $this->id, $this->data ); |
| } else { |
| $value = ProjectStatusReporter::valueOrDashes ( $value ); |
| } |
| return $value; |
| } |
| public function getSortValue() { |
| return ( string ) getSortValue ( $this->data, $this->id ); |
| } |
| } |