Open main menu

Extension:BugMilestone

MediaWiki extensions manual
OOjs UI icon advanced.svg
BugzillaMilestone
Release status: beta
Implementation Parser function
Description This extension adds a little Milestone dashboard a bit like Trac does, linked to a Bugzilla database.
Author(s) Bertrand Gorge http://www.epistema.com
Latest version 1.0
License No license specified
Download No link
Parameters
$GLOBALS['conf']['BugzillaMilestone'] = array(
        'bugzilla_url'  => 'http://bugzilla.your_company.com/',
        'database'      => "bugs",
        'user'          => "mysql_bug_user",
        'password'      => "mysql_bug_passwd");
Translate the BugMilestone extension if it is available at translatewiki.net
Check usage and version matrix.

This extension adds a little Milestone dashboard a bit like Trac does, linked to a Bugzilla database.

A version exists that works for MediaWiki 1.6 (not based on parser functions). See the discussion page to get the code.

Contents

InstallationEdit

Add and complete this at the end of LocalSettings.php :

 include_once('extensions/BugzillaMilestone.php');
 $GLOBALS['conf']['BugzillaMilestone'] = array(
        'bugzilla_url'  => 'http://bugzilla.your_company.com/',
        'database'      => "bugs",
        'user'          => "mysql_bug_user",
        'password'      => "mysql_bug_passwd");

Copy the following code into extensions/BugzillaMilestone.php :

<?php

# Define a setup function
$wgExtensionFunctions[] = 'wfBugzillaMilestone_Setup';
# Add a hook to initialise the magic word
$wgHooks['LanguageGetMagic'][]       = 'wfBugzillaMilestone_Magic';

$wgExtensionCredits['other'][] = array(
	'name' => 'BugzillaMilestone',
	'author' => 'Bertrand Gorge',
	'description' => 'for showing milestone dashboard, like in Trac',
	'url' => 'http://www.mediawiki.org/wiki/Extension:BugMilestone',
);

function wfBugzillaMilestone_Setup() {
	global $wgParser;
	# Set a function hook associating the "Milestone" magic word with our function
	$wgParser->setFunctionHook('Milestone', 'wfBugzillaMilestone_Render');
}

function wfBugzillaMilestone_Magic( &$magicWords, $langCode = '') {
	# Add the magic word
	# The first array element is case sensitive, in this case it is not case sensitive
	# All remaining elements are synonyms for our parser function
	$magicWords['Milestone'] = array( 0, 'Milestone' );
	# unless we return true, other parser functions extensions won't get loaded.
	return true;
}

function wfBugzillaMilestone_Render( &$parser, $Milestone = '') {
	# The parser function itself
	# The input parameters are wikitext with templates expanded
	# The output should be wikitext too

	$parser->disableCache();

	global $wgDBserver, $wgDBname, $wgDBUser, $wgDBPassword;

	$Source = $GLOBALS['conf']['BugzillaMilestone'];

	if (empty($Source['host']))
		$Source['host'] = $wgDBserver;
	if (empty($Source['database']))
		$Source['database'] = $wgDBname;
	if (empty($Source['user']))
		$Source['user'] = $wgDBUser;
	if (empty($Source['password']))
		$Source['password'] = $wgDBPassword;
	if (empty($Source['prefix']))
		$Source['prefix'] = "";

	$Link = @mysql_connect($Source['host'], $Source['user'], $Source['password'], true);
	if (!$Link)
		return pBugMilestone_NoConnection;

	if (!mysql_select_db($Source['database'], $Link)) {
		mysql_close($Link);
		return pBugMilestone_DBNotFound;
	}

	if (empty($Source['bugzilla_url']))
		$Source['bugzilla_url'] = 'http://yourbugzilla.installation.com/';

	$openURL =  $Source['bugzilla_url'] . 'buglist.cgi?query_format=advanced&target_milestone='.rawurlencode($Milestone).'&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED';
	$closedURL = $Source['bugzilla_url'] . 'buglist.cgi?query_format=advanced&target_milestone='.rawurlencode($Milestone).'&bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED';

	$OpenBugCountSQL = "SELECT COUNT(1) FROM " . $Source['prefix'] . "bugs WHERE bug_status IN ('UNCONFIRMED', 'NEW', 'ASSIGNED', 'REOPENED') AND target_milestone='".mysql_escape_string($Milestone)."'";
	$Result = @mysql_query($OpenBugCountSQL, $Link);
	if (!$Result) {
		mysql_close($Link);
		return pBugMilestone_QueryError;
	}
	if ($Row = mysql_fetch_row($Result))
		$OpenBugCount = $Row[0];

	$ClosedBugCountSQL = "SELECT COUNT(1) FROM " . $Source['prefix'] . "bugs WHERE bug_status IN ('RESOLVED', 'VERIFIED', 'CLOSED') AND target_milestone='".mysql_escape_string($Milestone)."'";
	$Result = @mysql_query($ClosedBugCountSQL, $Link);
	if (!$Result) {
		mysql_close($Link);
		return pBugMilestone_QueryError;
	}
	if ($Row = mysql_fetch_row($Result))
		$ClosedBugCount = $Row[0];

	mysql_free_result($Result);
	mysql_close($Link);

	$TotalBugsInMilestone = $ClosedBugCount + $OpenBugCount;
	if ($TotalBugsInMilestone > 0)
		$ClosedPercent = round($ClosedBugCount / $TotalBugsInMilestone * 100);
	else
		$ClosedPercent = 100;

	$strMiletone = '';

	if (empty($GLOBALS['BugMilestoneCSS'])) {
		$GLOBALS['BugMilestoneCSS'] = true;
		$strMiletone .= '<style type="text/css" media="print, screen, all">' . "\n";
		$strMiletone .= 'table.progress {' . "\n";
		$strMiletone .= ' border: 1px solid #d7d7d7;' . "\n";
		$strMiletone .= ' border-collapse: collapse;' . "\n";
		$strMiletone .= ' border-spacing: 0;' . "\n";
		$strMiletone .= ' float: left;' . "\n";
		$strMiletone .= ' margin: 0;' . "\n";
		$strMiletone .= ' padding: 0;' . "\n";
		$strMiletone .= ' empty-cells: show;' . "\n";
		$strMiletone .= '}' . "\n";
		$strMiletone .= 'table.progress a, table.progress :link, table.progress :visited,' . "\n";
		$strMiletone .= 'table.progress :link:hover, table.progress :visited:hover {' . "\n";
		$strMiletone .= ' border: none;' . "\n";
		$strMiletone .= ' display: block;' . "\n";
		$strMiletone .= ' width: 100%;' . "\n";
		$strMiletone .= ' height: 1.2em;' . "\n";
		$strMiletone .= ' padding: 0;' . "\n";
		$strMiletone .= ' margin: 0;' . "\n";
		$strMiletone .= ' text-decoration: none' . "\n";
		$strMiletone .= '}' . "\n";
		$strMiletone .= 'table.progress td { background: #fff; padding: 0 }' . "\n";
		$strMiletone .= 'table.progress td.closed { background: #bae0ba }' . "\n";
		$strMiletone .= 'table.progress td :hover { background: none }' . "\n";
		$strMiletone .= 'p.percent { font-size: 10px; line-height: 2.4em; margin: 0.9em 0 0 }' . "\n";
		$strMiletone .= 'ul.milestones { margin: 2em 0 0; padding: 0 }' . "\n";
		$strMiletone .= 'li.milestone { list-style: none; margin-bottom: 4em }' . "\n";
		$strMiletone .= '.milestone .info { white-space: nowrap }' . "\n";
		$strMiletone .= '.milestone .info h2 {' . "\n";
		$strMiletone .= ' background: #f7f7f7;' . "\n";
		$strMiletone .= ' border-bottom: 1px solid #d7d7d7;' . "\n";
		$strMiletone .= ' margin: 0;' . "\n";
		$strMiletone .= '}' . "\n";
		$strMiletone .= '.milestone .info .progress { margin: 1em 1em 0; width: 40em; max-width: 70% }' . "\n";
		$strMiletone .= '.milestone .info dl {' . "\n";
		$strMiletone .= ' font-size: 10px;' . "\n";
		$strMiletone .= ' font-style: italic;' . "\n";
		$strMiletone .= ' margin: 0 1em 2em;' . "\n";
		$strMiletone .= ' white-space: nowrap;' . "\n";
		$strMiletone .= ' clear: both;' . "\n";
		$strMiletone .= '}' . "\n";
		$strMiletone .= '.milestone .info dt { display: inline; margin-left: .5em }' . "\n";
		$strMiletone .= '.milestone .info dd { display: inline; margin: 0 1em 0 .5em }' . "\n";
		$strMiletone .= '</style>' . "\n";
	}

	$strMiletone .= '<ul class="milestones">  <li class="milestone">   <div class="info">' . "\n";
	$strMiletone .= '<table class="progress">' . "\n";
	$strMiletone .= ' <tr>' . "\n";
	$strMiletone .= '  <td class="closed" style="width: '.$ClosedPercent.'%;"><a target="_blank" href="'.$closedURL.'" title="'.$ClosedBugCount.' of '.$TotalBugsInMilestone.' tickets closed"></a></td>' . "\n";
	$strMiletone .= '  <td class="open" style="width: '.(100-$ClosedPercent).'%;"><a target="_blank" href="'.$openURL.'" title="'.$OpenBugCount.' of '.$TotalBugsInMilestone.' tickets active"></a></td>' . "\n";
	$strMiletone .= ' </tr>' . "\n";
	$strMiletone .= '</table>' . "\n";
	$strMiletone .= '<p class="percent">'.$ClosedPercent.'%</p>' . "\n";
	$strMiletone .= '<dl>' . "\n";
	$strMiletone .= ' <dt>Closed tickets:</dt>' . "\n";
	$strMiletone .= ' <dd><a target="_blank" href="'.$closedURL.'">'.$ClosedBugCount.'</a></dd>' . "\n";
	$strMiletone .= ' <dt>Active tickets:</dt>' . "\n";
	$strMiletone .= ' <dd><a target="_blank" href="'.$openURL.'">'.$OpenBugCount.'</a></dd>' . "\n";
	$strMiletone .= '</dl>' . "\n";
	$strMiletone .= '</div> </li>  </ul>' . "\n";

	return array($strMiletone, 'noparse' => true, 'isHTML' => true);
}

UsageEdit

Example: {{#Milestone: A milestone in Bugzilla}}

See alsoEdit

The Extension:BugSquish extension that gave me the id to link Bugzilla to MediaWiki...

CreditsEdit

Created by Bertrand Gorge - http://www.epistema.com/