Started on issue 544, extended commit details
* Scm.php: new SCM method "getChanges" which returns all available change information grouped by type * Monotone.php: implement getChanges via get_revision * <other scms>: rename "changes" member for getCommit to "diff" which matches better * Source.php: query the commit's changes and set them in the template * commit.html: render the changes, type-by-type. Link to the tree or the individual diff if applicable * styles.css: some initial style sheet work
This commit is contained in:
parent
51c42a65c5
commit
39c29dbe10
@ -316,6 +316,34 @@ class IDF_Scm
|
|||||||
throw new Pluf_Exception_NotImplemented();
|
throw new Pluf_Exception_NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all recorded changes which lead to the particular commit
|
||||||
|
* or revision.
|
||||||
|
*
|
||||||
|
* Example output:
|
||||||
|
*
|
||||||
|
* stdClass object {
|
||||||
|
* 'additions' => array('path/to/file', 'path/to/directory', ...),
|
||||||
|
* 'deletions' => array('path/to/file', 'path/to/directory', ...),
|
||||||
|
* 'renames' => array('old/path/to/file' => 'new/path/to/file', ...)
|
||||||
|
* 'patches' => array('path/to/file', ...),
|
||||||
|
* 'properties' => array('path/to/file' => array(
|
||||||
|
* 'propname' => 'propvalue', 'deletedprop' => null, ...)
|
||||||
|
* ),
|
||||||
|
* ...)
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Each member of the returned object is mandatory, but may contain
|
||||||
|
* an empty array if no changes were recorded.
|
||||||
|
*
|
||||||
|
* @param string A commit identifier
|
||||||
|
* @return object with arrays of individual changes
|
||||||
|
*/
|
||||||
|
public function getChanges($commit)
|
||||||
|
{
|
||||||
|
throw new Pluf_Exception_NotImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get latest changes.
|
* Get latest changes.
|
||||||
*
|
*
|
||||||
|
@ -431,10 +431,10 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$out = self::parseLog($log);
|
$out = self::parseLog($log);
|
||||||
$out[0]->changes = implode("\n", $change);
|
$out[0]->diff = implode("\n", $change);
|
||||||
} else {
|
} else {
|
||||||
$out = self::parseLog($out);
|
$out = self::parseLog($out);
|
||||||
$out[0]->changes = '';
|
$out[0]->diff = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$out[0]->branch = implode(', ', $this->inBranches($commit, null));
|
$out[0]->branch = implode(', ', $this->inBranches($commit, null));
|
||||||
|
@ -359,7 +359,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$out = self::parseLog($log, 6);
|
$out = self::parseLog($log, 6);
|
||||||
$out[0]->changes = implode("\n", $change);
|
$out[0]->diff = implode("\n", $change);
|
||||||
return $out[0];
|
return $out[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,6 +599,75 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getChanges()
|
||||||
|
*/
|
||||||
|
public function getChanges($commit)
|
||||||
|
{
|
||||||
|
$revs = $this->_resolveSelector($commit);
|
||||||
|
if (count($revs) == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$revision = $revs[0];
|
||||||
|
$out = $this->stdio->exec(array('get_revision', $revision));
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
||||||
|
|
||||||
|
$return = (object) array(
|
||||||
|
'additions' => array(),
|
||||||
|
'deletions' => array(),
|
||||||
|
'renames' => array(),
|
||||||
|
'patches' => array(),
|
||||||
|
'properties' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($stanzas as $stanza) {
|
||||||
|
if ($stanza[0]['key'] == 'format_version' ||
|
||||||
|
$stanza[0]['key'] == 'old_revision' ||
|
||||||
|
$stanza[0]['key'] == 'new_manifest')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ($stanza[0]['key'] == 'add_file' ||
|
||||||
|
$stanza[0]['key'] == 'add_dir') {
|
||||||
|
$return->additions[] = $stanza[0]['values'][0];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stanza[0]['key'] == 'delete') {
|
||||||
|
$return->deletions[] = $stanza[0]['values'][0];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stanza[0]['key'] == 'rename') {
|
||||||
|
$return->renames[$stanza[0]['values'][0]] =
|
||||||
|
$stanza[1]['values'][0];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stanza[0]['key'] == 'patch') {
|
||||||
|
$return->patches[] = $stanza[0]['values'][0];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stanza[0]['key'] == 'clear' ||
|
||||||
|
$stanza[0]['key'] == 'set') {
|
||||||
|
|
||||||
|
$filename = $stanza[0]['values'][0];
|
||||||
|
if (!array_key_exists($filename, $return->properties)) {
|
||||||
|
$return->properties[$filename] = array();
|
||||||
|
}
|
||||||
|
$key = $stanza[1]['values'][0];
|
||||||
|
$value = null;
|
||||||
|
if (isset($stanza[2])) {
|
||||||
|
$value = $stanza[2]['values'][0];
|
||||||
|
}
|
||||||
|
$return->properties[$filename][$key] = $value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IDF_Scm::getCommit()
|
* @see IDF_Scm::getCommit()
|
||||||
*/
|
*/
|
||||||
@ -626,7 +695,7 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
$res['branch'] = implode(', ', $certs['branch']);
|
$res['branch'] = implode(', ', $certs['branch']);
|
||||||
$res['commit'] = $revs[0];
|
$res['commit'] = $revs[0];
|
||||||
|
|
||||||
$res['changes'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
|
$res['diff'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
|
||||||
|
|
||||||
return (object) $res;
|
return (object) $res;
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
$res['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $xml->logentry->date));
|
$res['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $xml->logentry->date));
|
||||||
$res['title'] = (string) $xml->logentry->msg;
|
$res['title'] = (string) $xml->logentry->msg;
|
||||||
$res['commit'] = (string) $xml->logentry['revision'];
|
$res['commit'] = (string) $xml->logentry['revision'];
|
||||||
$res['changes'] = ($getdiff) ? $this->getDiff($commit) : '';
|
$res['diff'] = ($getdiff) ? $this->getDiff($commit) : '';
|
||||||
$res['tree'] = '';
|
$res['tree'] = '';
|
||||||
$res['branch'] = '';
|
$res['branch'] = '';
|
||||||
return (object) $res;
|
return (object) $res;
|
||||||
|
@ -297,8 +297,9 @@ class IDF_Views_Source
|
|||||||
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
||||||
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
||||||
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
|
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
|
||||||
$diff = new IDF_Diff($cobject->changes);
|
$diff = new IDF_Diff($cobject->diff);
|
||||||
$diff->parse();
|
$diff->parse();
|
||||||
|
$changes = $scm->getChanges($commit);
|
||||||
$scmConf = $request->conf->getVal('scm', 'git');
|
$scmConf = $request->conf->getVal('scm', 'git');
|
||||||
$branches = $scm->getBranches();
|
$branches = $scm->getBranches();
|
||||||
$in_branches = $scm->inBranches($cobject->commit, '');
|
$in_branches = $scm->inBranches($cobject->commit, '');
|
||||||
@ -311,6 +312,7 @@ class IDF_Views_Source
|
|||||||
'diff' => $diff,
|
'diff' => $diff,
|
||||||
'cobject' => $cobject,
|
'cobject' => $cobject,
|
||||||
'commit' => $commit,
|
'commit' => $commit,
|
||||||
|
'changes' => $changes,
|
||||||
'branches' => $branches,
|
'branches' => $branches,
|
||||||
'tree_in' => $in_branches,
|
'tree_in' => $in_branches,
|
||||||
'tags' => $tags,
|
'tags' => $tags,
|
||||||
|
@ -18,20 +18,45 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br/><br/>{issuetext $cobject.full_message, $request, true, false, true, true, true}{/if}</td>
|
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br/><br/>{issuetext $cobject.full_message, $request, true, false, true, true, true}{/if}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{if count($diff.files)}
|
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Files:'}</strong></th>
|
<th><strong>{trans 'Changes:'}</strong></th>
|
||||||
<td>
|
<td>
|
||||||
{foreach $diff.files as $filename=>$diffdef}
|
<table class="changes">
|
||||||
{assign $ndiff = count($diffdef['chunks'])}
|
{foreach $changes.deletions as $filename}
|
||||||
<a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a> (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>)<br/>
|
<tr><td>D</td><td>{$filename}{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
{foreach $changes.renames as $oldname => $newname}
|
||||||
|
<tr><td>R</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $newname)}">{$oldname} -> {$newname}</a></td></tr>
|
||||||
|
{/foreach}
|
||||||
|
{foreach $changes.additions as $filename}
|
||||||
|
<tr><td>A</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
||||||
|
{/foreach}
|
||||||
|
{foreach $changes.patches as $filename}
|
||||||
|
{assign $ndiff = count($diff.files[$filename]['chunks'])}
|
||||||
|
<tr><td>M</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>){/if}</td></tr>
|
||||||
|
{/foreach}
|
||||||
|
{foreach $changes.properties as $filename => $properties}
|
||||||
|
<tr><td>P</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>
|
||||||
|
<table class="properties">
|
||||||
|
{foreach $properties as $key => $value}
|
||||||
|
<tr><td>{$key}</td>
|
||||||
|
{if $value == null}
|
||||||
|
<td class="removed">{trans 'removed'}</td>
|
||||||
|
{else}
|
||||||
|
<td>{$value}</td>
|
||||||
|
{/if}
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</table>
|
||||||
|
</td></tr>
|
||||||
|
{/foreach}
|
||||||
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/if}
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{if count($diff.files)}
|
{if count($diff.files)}
|
||||||
<h2>{trans 'Change Details'}</h2>
|
<h2>{trans 'File differences'}</h2>
|
||||||
|
|
||||||
{$diff.as_html()}
|
{$diff.as_html()}
|
||||||
{/if}{if count($diff.files) or $large_commit}
|
{/if}{if count($diff.files) or $large_commit}
|
||||||
|
@ -504,6 +504,21 @@ table.commit th {
|
|||||||
table.commit td, table.commit th {
|
table.commit td, table.commit th {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
table.commit table.changes td {
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
table.commit table.changes table.properties {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
table.commit table.changes table.properties tr:nth-child(even) {
|
||||||
|
background: #E4E8E0;
|
||||||
|
}
|
||||||
|
table.commit table.changes table.properties td {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
table.commit table.changes table.properties td.removed {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* syntax highlighting of diffs
|
* syntax highlighting of diffs
|
||||||
|
Loading…
Reference in New Issue
Block a user