Compare commits
16 Commits
feature.co
...
feature.se
Author | SHA1 | Date | |
---|---|---|---|
|
9a8bd464a3 | ||
|
9e2ea7404b | ||
|
160d11b89b | ||
|
85978a4d18 | ||
|
e1e7696d53 | ||
|
695428075b | ||
|
e7c2e721b4 | ||
|
13fad756ab | ||
|
1f0791df0e | ||
|
a2c832a130 | ||
|
b17de014ec | ||
|
b1b72190e1 | ||
|
2ff2f888bc | ||
|
57c2389aae | ||
|
d54c86f813 | ||
|
05a9697007 |
1
AUTHORS
1
AUTHORS
@@ -33,6 +33,7 @@ Much appreciated contributors (in alphabetical order):
|
||||
Samuel Suther <info@suther.de> - German translation
|
||||
Sindre R. Myren <sindrero@stud.ntnu.no>
|
||||
Stewart Platt <stew@futurete.ch>
|
||||
Stéphane Baron <sbaron>
|
||||
Thomas Keller <me@thomaskeller.biz> - Monotone support
|
||||
Vladimir Solomatin <slash>
|
||||
William Martin <william.martin@lcpc.fr>
|
||||
|
@@ -16,7 +16,7 @@ or newer to properly run this version of Indefero!
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- The SVN interface acts more robust if an underlying repository has been restructured (issue 364)
|
||||
- The SVN interface acts more robust if an underlying repository has been restructured (issues 364 and 721)
|
||||
- monotone zip archive entries now all carry the revision date as mtime (issue 645)
|
||||
- Timeline only displays filter options for items a user has actually access to (issue 655)
|
||||
- The log, tags and branches parsers for Mercurial are more robust now (issue 663)
|
||||
@@ -29,12 +29,18 @@ or newer to properly run this version of Indefero!
|
||||
- Prevent a timeout from popping up when Usher is restarted (issue 695)
|
||||
- The SyncMonotone plugin now cleans up partial artifacts it created during the addition of
|
||||
a new project or monotone key, in case an error popped up in the middle (issue 697)
|
||||
- Indefero now sends the MD5 checksum as HTTP header when downloading a file from the
|
||||
download area. Additionally, a unneeded redirect has been removed. (issue 716)
|
||||
- Source links without a specific revision did not work due to a wrong regex (issue 730)
|
||||
- Better error detection and reporting in the SyncMonotone plugin
|
||||
ATTENTION: This needs Pluf 46b7f251 or newer!
|
||||
- Fix the branch links users of the Subversion frontend get when they enter a wrong revision
|
||||
and only display this list if there are any branches available for all SCMs
|
||||
- If git's author name is not encoded in an UTF-8 compatible encoding, skip the author lookup,
|
||||
as we have no information what the author string is actually encoded in
|
||||
- Indefero no longer displays an empty parents paragraph in the commit view for root revisions of
|
||||
a git repository
|
||||
- Indefero now only shows the tags of the closed and not the open issues in the closed issues list
|
||||
|
||||
## Documentation
|
||||
|
||||
|
@@ -88,6 +88,7 @@ class IDF_Middleware
|
||||
'showuser' => 'IDF_Template_ShowUser',
|
||||
'ashowuser' => 'IDF_Template_AssignShowUser',
|
||||
'appversion' => 'IDF_Template_AppVersion',
|
||||
'upload' => 'IDF_Template_Tag_UploadUrl',
|
||||
));
|
||||
$params['modifiers'] = array_merge($params['modifiers'],
|
||||
array(
|
||||
|
@@ -132,7 +132,7 @@ class IDF_Project extends Pluf_Model
|
||||
}
|
||||
return $projects[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of open/closed issues.
|
||||
*
|
||||
@@ -167,7 +167,7 @@ GROUP BY uid";
|
||||
$key = ($v['id'] === '-1') ? null : $v['id'];
|
||||
$ownerStatistics[$key] = (int)$v['nb'];
|
||||
}
|
||||
|
||||
|
||||
arsort($ownerStatistics);
|
||||
|
||||
return $ownerStatistics;
|
||||
@@ -178,9 +178,10 @@ GROUP BY uid";
|
||||
*
|
||||
* @param string Status ('open'), 'closed'
|
||||
* @param IDF_Tag Subfilter with a label (null)
|
||||
* @param array Restrict further to a list of ids
|
||||
* @return int Count
|
||||
*/
|
||||
public function getIssueCountByStatus($status='open', $label=null)
|
||||
public function getIssueCountByStatus($status='open', $label=null, $ids=array())
|
||||
{
|
||||
switch ($status) {
|
||||
case 'open':
|
||||
@@ -203,12 +204,48 @@ GROUP BY uid";
|
||||
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
|
||||
$sql->SAnd($sql2);
|
||||
}
|
||||
if (count($ids) > 0) {
|
||||
$sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
|
||||
$sql->SAnd($sql2);
|
||||
}
|
||||
$params = array('filter' => $sql->gen());
|
||||
if (!is_null($label)) { $params['view'] = 'join_tags'; }
|
||||
$gissue = new IDF_Issue();
|
||||
return $gissue->getCount($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tags for a specific list of issues.
|
||||
*
|
||||
* @param string Status ('open') or 'closed'
|
||||
* @param array A list of issue ids
|
||||
* @return array An array of tag objects
|
||||
*/
|
||||
public function getTagsByIssues($issue_ids=array())
|
||||
{
|
||||
// make the below query always a valid one
|
||||
if (count($issue_ids) == 0) $issue_ids[] = 0;
|
||||
|
||||
$assocTable = $this->_con->pfx.'idf_issue_idf_tag_assoc';
|
||||
$query = sprintf(
|
||||
'SELECT DISTINCT idf_tag_id FROM %s '.
|
||||
'WHERE idf_issue_id IN (%s) '.
|
||||
'GROUP BY idf_tag_id',
|
||||
$assocTable, implode(',', $issue_ids)
|
||||
);
|
||||
|
||||
$db = Pluf::db();
|
||||
$dbData = $db->select($query);
|
||||
$ids = array(0);
|
||||
foreach ($dbData as $data) {
|
||||
$ids[] = $data['idf_tag_id'];
|
||||
}
|
||||
|
||||
$sql = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
|
||||
$model = new IDF_Tag();
|
||||
return $model->getList(array('filter' => $sql->gen()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the open/closed tag ids as they are often used when doing
|
||||
* listings.
|
||||
@@ -415,7 +452,11 @@ GROUP BY uid";
|
||||
foreach ($this->_con->select($sql) as $idc) {
|
||||
$tag = new IDF_Tag($idc['id']);
|
||||
$tag->nb_use = $idc['nb_use'];
|
||||
$tags[] = $tag;
|
||||
// group by class
|
||||
if (!array_key_exists($tag->class, $tags)) {
|
||||
$tags[$tag->class] = array();
|
||||
}
|
||||
$tags[$tag->class][] = $tag;
|
||||
}
|
||||
return new Pluf_Template_ContextVars($tags);
|
||||
}
|
||||
|
@@ -646,7 +646,11 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
|
||||
$c['title'] = IDF_Commit::toUTF8($c['title']);
|
||||
if (isset($c['parents'])) {
|
||||
$c['parents'] = explode(' ', trim($c['parents']));
|
||||
$c['parents'] = preg_split('/ /', trim($c['parents']), -1, PREG_SPLIT_NO_EMPTY);
|
||||
} else {
|
||||
// this is actually an error state because we should _always_
|
||||
// be able to parse the parents line with every git version
|
||||
$c['parents'] = null;
|
||||
}
|
||||
$res[] = (object) $c;
|
||||
return $res;
|
||||
|
@@ -33,7 +33,6 @@
|
||||
*/
|
||||
class IDF_Scm_Svn extends IDF_Scm
|
||||
{
|
||||
|
||||
public $username = '';
|
||||
public $password = '';
|
||||
private $assoc = array('dir' => 'tree',
|
||||
@@ -48,11 +47,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
|
||||
public function isAvailable()
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('info', '--xml'), $this->repo);
|
||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::isAvailable', $cmd);
|
||||
|
||||
try {
|
||||
@@ -163,12 +158,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return IDF_Scm::REVISION_VALID;
|
||||
}
|
||||
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('info'), $this->repo, $rev);
|
||||
self::exec('IDF_Scm_Svn::validateRevision', $cmd, $out, $ret);
|
||||
|
||||
if ($ret == 0)
|
||||
@@ -190,12 +180,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
}
|
||||
|
||||
// Else, test the path on revision
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('info', '--xml'),
|
||||
$this->repo.'/'.self::smartEncode($path),
|
||||
$rev);
|
||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::testHash', $cmd);
|
||||
|
||||
// If exception is thrown, return false
|
||||
@@ -217,12 +204,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
|
||||
public function getTree($commit, $folder='/', $branch=null)
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --xml --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($commit),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($folder)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('ls', '--xml'),
|
||||
$this->repo.'/'.self::smartEncode($folder),
|
||||
$commit);
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getTree', $cmd));
|
||||
$res = array();
|
||||
$folder = (strlen($folder) and ($folder != '/')) ? $folder.'/' : '';
|
||||
@@ -258,12 +242,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
if (isset($this->cache['commitmess'][$rev])) {
|
||||
return $this->cache['commitmess'][$rev];
|
||||
}
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml --limit 1 --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('log', '--xml', '--limit', '1'), $this->repo, $rev);
|
||||
try {
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
||||
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
||||
@@ -279,12 +258,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
if ($rev == null) {
|
||||
$rev = 'HEAD';
|
||||
}
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($filename)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('info', '--xml'),
|
||||
$this->repo.'/'.self::smartEncode($filename), $rev);
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getPathInfo', $cmd));
|
||||
if (!isset($xml->entry)) {
|
||||
return false;
|
||||
@@ -306,12 +281,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
|
||||
public function getFile($def, $cmd_only=false)
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' cat --no-auth-cache --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($def->rev),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($def->fullpath)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('cat'),
|
||||
$this->repo.'/'.self::smartEncode($def->fullpath),
|
||||
$def->rev);
|
||||
return ($cmd_only) ?
|
||||
$cmd : self::shell_exec('IDF_Scm_Svn::getFile', $cmd);
|
||||
}
|
||||
@@ -327,11 +299,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return $this->cache['branches'];
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --username=%s --password=%s --revision=HEAD %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/branches'));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('ls'), $this->repo.'/branches', 'HEAD');
|
||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
foreach ($out as $entry) {
|
||||
@@ -342,11 +310,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
}
|
||||
}
|
||||
ksort($res);
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --username=%s --password=%s --revision=HEAD %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/trunk'));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
|
||||
$cmd = $this->svnCmd(array('info'), $this->repo.'/trunk', 'HEAD');
|
||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
$res = array('trunk' => 'trunk') + $res;
|
||||
@@ -366,11 +331,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return $this->cache['tags'];
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --username=%s --password=%s --revision=HEAD %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/tags'));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('ls'), $this->repo.'/tags', 'HEAD');
|
||||
self::exec('IDF_Scm_Svn::getTags', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
foreach ($out as $entry) {
|
||||
@@ -423,12 +384,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return false;
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml --limit 1 -v --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($commit),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('log', '--xml', '--limit', '1', '-v'),
|
||||
$this->repo, $commit);
|
||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getCommit', $cmd);
|
||||
$xml = simplexml_load_string($xmlRes);
|
||||
$res['author'] = (string) $xml->logentry->author;
|
||||
@@ -470,12 +427,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
private function getDiff($rev='HEAD')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' diff --no-auth-cache -c %s --username=%s --password=%s %s',
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('diff', '-c', $rev), $this->repo);
|
||||
return self::shell_exec('IDF_Scm_Svn::getDiff', $cmd);
|
||||
}
|
||||
|
||||
@@ -487,13 +439,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
if ($this->validateRevision($commit) != IDF_Scm::REVISION_VALID) {
|
||||
return null;
|
||||
}
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --xml -v --no-auth-cache -r %s --username=%s --password=%s %s',
|
||||
escapeshellarg($commit),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = $this->svnCmd(array('log', '--xml', '-v'), $this->repo, $commit);
|
||||
$out = array();
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$out = self::shell_exec('IDF_Scm_Svn::getChanges', $cmd);
|
||||
$xml = simplexml_load_string($out);
|
||||
if (count($xml) == 0) {
|
||||
@@ -570,20 +517,15 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
*
|
||||
* @return array Changes.
|
||||
*/
|
||||
public function getChangeLog($branch=null, $n=10)
|
||||
public function getChangeLog($rev=null, $n=10)
|
||||
{
|
||||
if ($branch != 'HEAD' and !preg_match('/^\d+$/', $branch)) {
|
||||
if ($rev != 'HEAD' and !preg_match('/^\d+$/', $rev)) {
|
||||
// we accept only revisions or HEAD
|
||||
$branch = 'HEAD';
|
||||
$rev = 'HEAD';
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml -v --limit %s --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($n),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($branch),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('log', '--xml', '-v', '--limit', $n),
|
||||
$this->repo.'@'.$rev);
|
||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getChangeLog', $cmd);
|
||||
$xml = simplexml_load_string($xmlRes);
|
||||
foreach ($xml->logentry as $entry) {
|
||||
@@ -609,12 +551,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
public function getProperties($rev, $path='')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' proplist --no-auth-cache --xml --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('proplist', '--xml'),
|
||||
$this->repo.'/'.self::smartEncode($path), $rev);
|
||||
$xmlProps = self::shell_exec('IDF_Scm_Svn::getProperties', $cmd);
|
||||
$props = simplexml_load_string($xmlProps);
|
||||
|
||||
@@ -643,13 +581,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
private function getProperty($property, $rev, $path='')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' propget --no-auth-cache --xml %s --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($property),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('propget', $property, '--xml'),
|
||||
$this->repo.'/'.self::smartEncode($path), $rev);
|
||||
$xmlProp = self::shell_exec('IDF_Scm_Svn::getProperty', $cmd);
|
||||
$prop = simplexml_load_string($xmlProp);
|
||||
|
||||
@@ -666,16 +599,38 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
public function getLastCommit($rev='HEAD')
|
||||
{
|
||||
$xmlInfo = '';
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s --revision=%s %s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$cmd = $this->svnCmd(array('info', '--xml'), $this->repo, $rev);
|
||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::getLastCommit', $cmd);
|
||||
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
return (string) $xml->entry->commit['revision'];
|
||||
}
|
||||
|
||||
private function svnCmd($args = array(), $repoarg = null, $revarg = null)
|
||||
{
|
||||
$cmdline = array();
|
||||
$cmdline[] = Pluf::f('idf_exec_cmd_prefix', '');
|
||||
$cmdline[] = Pluf::f('svn_path', 'svn');
|
||||
$cmdline[] = '--no-auth-cache';
|
||||
$cmdline[] = '--username='.escapeshellarg($this->username);
|
||||
$cmdline[] = '--password='.escapeshellarg($this->password);
|
||||
|
||||
foreach ($args as $arg) {
|
||||
$cmdline[] = escapeshellarg($arg);
|
||||
}
|
||||
|
||||
if ($repoarg != null) {
|
||||
if ($revarg != null) {
|
||||
$repoarg .= '@'.$revarg;
|
||||
}
|
||||
$cmdline[] = escapeshellarg($repoarg);
|
||||
}
|
||||
|
||||
if ($revarg != null) {
|
||||
$cmdline[] = '--revision='.escapeshellarg($revarg);
|
||||
}
|
||||
|
||||
return implode(' ', $cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,7 +58,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
implode('|', $nouns);
|
||||
$text = IDF_Template_safePregReplace('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
|
||||
array($this, 'callbackCommits'), $text);
|
||||
$text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
|
||||
$text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))?(?:#(\d+))?=im',
|
||||
array($this, 'callbackSource'), $text);
|
||||
}
|
||||
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
||||
|
35
src/IDF/Template/Tag/UploadUrl.php
Normal file
35
src/IDF/Template/Tag/UploadUrl.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero 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 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
class IDF_Template_Tag_UploadUrl extends Pluf_Template_Tag
|
||||
{
|
||||
function start($file='')
|
||||
{
|
||||
echo IDF_Template_Tag_UploadUrl::url($file);
|
||||
}
|
||||
|
||||
public static function url($file='')
|
||||
{
|
||||
return Pluf::f('url_upload', Pluf_Template_Tag_MediaUrl::url() . '/upload') . $file;
|
||||
}
|
||||
}
|
@@ -319,13 +319,11 @@ class IDF_Views_Download
|
||||
$pag->no_results_text = __('No downloads were found.');
|
||||
$pag->sort_order = array('creation_dtime', 'DESC');
|
||||
$pag->setFromRequest($request);
|
||||
$tags = $prj->getTagCloud('downloads');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'label' => $tag,
|
||||
'downloads' => $pag,
|
||||
'tags' => $tags,
|
||||
'dlabel' => $dtag,
|
||||
),
|
||||
$request);
|
||||
|
@@ -71,7 +71,9 @@ class IDF_Views_Issue
|
||||
'page_title' => $title,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'issues' => $pag);
|
||||
'issues' => $pag,
|
||||
'cloud' => 'issues',
|
||||
);
|
||||
if ($api) return $params;
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
||||
$params, $request);
|
||||
@@ -88,7 +90,7 @@ class IDF_Views_Issue
|
||||
$ownerStatistics = array();
|
||||
$status = array();
|
||||
$isTrackerEmpty = false;
|
||||
|
||||
|
||||
$prj = $request->project;
|
||||
$opened = $prj->getIssueCountByStatus('open');
|
||||
$closed = $prj->getIssueCountByStatus('closed');
|
||||
@@ -102,7 +104,7 @@ class IDF_Views_Issue
|
||||
$status['Open'] = array($opened, (int)(100 * $opened / ($opened + $closed)));
|
||||
$status['Closed'] = array($closed, (int)(100 * $closed / ($opened + $closed)));
|
||||
}
|
||||
|
||||
|
||||
if ($opened > 0) {
|
||||
// Issue owner statistics
|
||||
$owners = $prj->getIssueCountByOwner('open');
|
||||
@@ -117,9 +119,11 @@ class IDF_Views_Issue
|
||||
}
|
||||
|
||||
// Issue class tag statistics
|
||||
$tags = $prj->getTagCloud();
|
||||
foreach ($tags as $t) {
|
||||
$tagStatistics[$t->class][$t->name] = array($t->nb_use, $t->id);
|
||||
$grouped_tags = $prj->getTagCloud();
|
||||
foreach ($grouped_tags as $class => $tags) {
|
||||
foreach ($tags as $tag) {
|
||||
$tagStatistics[$class][$tag->name] = array($tag->nb_use, $tag->id);
|
||||
}
|
||||
}
|
||||
foreach($tagStatistics as $k => $v) {
|
||||
$nbIssueInClass = 0;
|
||||
@@ -130,15 +134,15 @@ class IDF_Views_Issue
|
||||
$tagStatistics[$k][$kk] = array($vv[0], (int)(100 * $vv[0] / $nbIssueInClass), $vv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sort
|
||||
krsort($tagStatistics);
|
||||
arsort($ownerStatistics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$title = sprintf(__('Summary of tracked issues in %s.'), (string) $prj);
|
||||
|
||||
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/summary.html',
|
||||
array('page_title' => $title,
|
||||
'trackerEmpty' => $isTrackerEmpty,
|
||||
@@ -149,7 +153,7 @@ class IDF_Views_Issue
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* View the issues watch list of a given user.
|
||||
* Limited to a specified project
|
||||
@@ -429,45 +433,142 @@ class IDF_Views_Issue
|
||||
|
||||
public $search_precond = array('IDF_Precondition::accessIssues');
|
||||
public function search($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
return $this->doSearch($request, $query, 'open');
|
||||
}
|
||||
|
||||
public $searchStatus_precond = array('IDF_Precondition::accessIssues');
|
||||
public function searchStatus($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
|
||||
return $this->doSearch($request, $query, $status);
|
||||
}
|
||||
|
||||
public $searchLabel_precond = array('IDF_Precondition::accessIssues');
|
||||
public function searchLabel($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$tag_id = intval($match[2]);
|
||||
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
|
||||
return $this->doSearch($request, $query, $status, $tag_id);
|
||||
}
|
||||
|
||||
private function doSearch($request, $query, $status, $tag_id=null)
|
||||
{
|
||||
$prj = $request->project;
|
||||
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||
array($prj->shortname));
|
||||
if (trim($query) == '') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$q = $request->REQUEST['q'];
|
||||
$title = sprintf(__('Search Issues - %s'), $q);
|
||||
$issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Issue'));
|
||||
if (count($issues) > 100) {
|
||||
// no more than 100 results as we do not care
|
||||
$issues->results = array_slice($issues->results, 0, 100);
|
||||
|
||||
$tag = null;
|
||||
if ($tag_id !== null) {
|
||||
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $tag_id);
|
||||
}
|
||||
|
||||
$title = sprintf(__('Search issues - %s'), $query);
|
||||
if ($status === 'closed') {
|
||||
$title = sprintf(__('Search closed issues - %s'), $query);
|
||||
}
|
||||
|
||||
// using Plufs ResultSet implementation here is inefficient, because
|
||||
// it makes a SELECT for each item and does not allow for further
|
||||
// filtering neither, so we just return the ids and filter by them
|
||||
// and other things in the next round
|
||||
$results = IDF_Search::mySearch($query, $prj, 'IDF_Issue');
|
||||
|
||||
$issue_ids = array(0);
|
||||
foreach ($results as $result) {
|
||||
$issue_ids[] = $result['model_id'];
|
||||
}
|
||||
|
||||
$otags = $prj->getTagIdsByStatus($status);
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$sql = new Pluf_SQL(
|
||||
'id IN ('.implode(',', $issue_ids).') '.
|
||||
'AND status IN ('.implode(', ', $otags).') '.
|
||||
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
|
||||
);
|
||||
$model = new IDF_Issue();
|
||||
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
|
||||
|
||||
// we unfortunately loose the original sort order,
|
||||
// so we manually have to apply it here again
|
||||
$sorted_issues = new ArrayObject();
|
||||
$filtered_issue_ids = array(0);
|
||||
foreach ($issue_ids as $issue_id) {
|
||||
foreach ($issues as $issue) {
|
||||
if ($issue->id != $issue_id)
|
||||
continue;
|
||||
if (array_key_exists($issue_id, $sorted_issues))
|
||||
continue;
|
||||
$sorted_issues[$issue_id] = $issue;
|
||||
$filtered_issue_ids[] = $issue_id;
|
||||
}
|
||||
}
|
||||
|
||||
$pag = new Pluf_Paginator();
|
||||
$pag->items = $issues;
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->items = $sorted_issues;
|
||||
$pag->item_extra_props = array(
|
||||
'project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user
|
||||
);
|
||||
$pag->summary = __('This table shows the found issues.');
|
||||
$pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display);
|
||||
$pag->items_per_page = 100;
|
||||
$pag->configure(array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
));
|
||||
// disable paginating
|
||||
$pag->items_per_page = PHP_INT_MAX;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
$params = array('page_title' => $title,
|
||||
'issues' => $pag,
|
||||
'q' => $q,
|
||||
);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
||||
|
||||
if ($tag_id === null) {
|
||||
$pag->action = array('IDF_Views_Issue::searchStatus',
|
||||
array($prj->shortname, $status),
|
||||
array('q'=> $query),
|
||||
);
|
||||
} else {
|
||||
$pag->action = array('IDF_Views_Issue::searchLabel',
|
||||
array($prj->shortname, $tag_id, $status),
|
||||
array('q'=> $query),
|
||||
);
|
||||
}
|
||||
|
||||
// get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
|
||||
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
|
||||
|
||||
// query the available tags for this search result
|
||||
$all_tags = $prj->getTagsByIssues($filtered_issue_ids);
|
||||
$grouped_tags = array();
|
||||
foreach ($all_tags as $atag) {
|
||||
// group by class
|
||||
if (!array_key_exists($atag->class, $grouped_tags)) {
|
||||
$grouped_tags[$atag->class] = array();
|
||||
}
|
||||
$grouped_tags[$atag->class][] = $atag;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'page_title' => $title,
|
||||
'issues' => $pag,
|
||||
'query' => $query,
|
||||
'status' => $status,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'tag' => $tag,
|
||||
'all_tags' => $grouped_tags,
|
||||
);
|
||||
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
||||
}
|
||||
|
||||
public $view_precond = array('IDF_Precondition::accessIssues');
|
||||
|
@@ -152,13 +152,11 @@ class IDF_Views_Wiki
|
||||
$pag->items_per_page = 25;
|
||||
$pag->no_results_text = __('No documentation pages were found.');
|
||||
$pag->setFromRequest($request);
|
||||
$tags = $prj->getTagCloud('wiki');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'label' => $tag,
|
||||
'pages' => $pag,
|
||||
'tags' => $tags,
|
||||
'dlabel' => $dtag,
|
||||
),
|
||||
$request);
|
||||
|
@@ -117,7 +117,7 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'index');
|
||||
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
@@ -128,6 +128,16 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'search');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/status/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'searchStatus');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/label/(\d+)/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'searchLabel');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
|
@@ -7,7 +7,7 @@
|
||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>
|
||||
| <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} |
|
||||
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
||||
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
|
||||
<input accesskey="4" type="text" value="{$query}" name="q" size="20" />
|
||||
<input type="submit" name="s" value="{trans 'Search'}" />
|
||||
</form>
|
||||
{if $inIssue} |
|
||||
|
@@ -8,16 +8,15 @@
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Label:'}</strong>
|
||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
|
||||
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
|
||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||
{/blocktrans}{if $completion}
|
||||
{/blocktrans}
|
||||
<p><strong>{trans 'Label:'}</strong>
|
||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
|
||||
{if $completion}
|
||||
<p><strong>{trans 'Completion:'}</strong> {$completion}</p>
|
||||
{/if}
|
||||
|
||||
|
||||
{/block}
|
||||
|
@@ -13,6 +13,5 @@
|
||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
|
||||
{assign $cloud = 'issues'}
|
||||
{include 'idf/tags-cloud.html'}
|
||||
{/block}
|
||||
|
@@ -8,5 +8,25 @@
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Found issues:'}</strong> {$issues.nb_items}</p>
|
||||
{aurl 'open_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'), array('q' => $query)}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)}
|
||||
{if $tag != null}
|
||||
{aurl 'open_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'), array('q' => $query)}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)}
|
||||
{/if}
|
||||
{blocktrans}
|
||||
<p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||
{if $tag !== null}
|
||||
{blocktrans}<p><strong>Label:</strong>
|
||||
<a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans}
|
||||
{else}
|
||||
{* yes, this is duplicated from tags-cloud.html, but the code there cannot be easily overridden *}
|
||||
<div id="tagscloud" class="smaller"><dl>{foreach $all_tags as $class => $labels}
|
||||
<dt class="label">{$class}</dt>
|
||||
{foreach $labels as $idx => $label}
|
||||
{aurl 'url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $label.id, $status), array('q'=> $query)}
|
||||
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
|
||||
{/foreach}{/foreach}</dl></p>
|
||||
{/if}
|
||||
{/block}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
{assign $submitter_data = $c.get_submitter_data()}
|
||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
|
||||
{if $submitter_data.avatar != ''}
|
||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
|
||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
|
||||
{else}
|
||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||
{/if}
|
||||
|
@@ -5,17 +5,4 @@
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Review::create', array($project.shortname)}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
{*
|
||||
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||
{assign $class = ''}{assign $i = 0}
|
||||
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
|
||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
|
||||
<a href="{$url}" class="label">{$label.name}</a>,{assign $class = $label.class}{assign $i = $i + 1}{/foreach}</p>
|
||||
*}{/block}
|
||||
|
@@ -109,7 +109,7 @@ to propose more contributions</strong>.
|
||||
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $submitter = $c.get_submitter()}{assign $submitter_data = $c.get_submitter_data()}
|
||||
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} issue-comment-last{/if}" id="ic{$c.id}">
|
||||
{if $submitter_data.avatar != ''}
|
||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
|
||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
|
||||
{else}
|
||||
<img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||
{/if}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
{assign $class = ''}{assign $i = 0}
|
||||
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $label}
|
||||
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $class => $labels}
|
||||
<dt class="label">{$class}</dt>
|
||||
{foreach $labels as $idx => $label}
|
||||
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
|
||||
{if $class != $label.class}<dt class="label">{$label.class}</dt>{assign $i = 0}{/if}
|
||||
<dd><a href="{$url}" class="label">{$label.name},</a></dd>
|
||||
{assign $class = $label.class}
|
||||
{assign $i = $i + 1}
|
||||
{/foreach}</dl></p>
|
||||
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
|
||||
{/foreach}{/foreach}</dl></p>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th style="text-align: right">{if $user_data.avatar != ''}
|
||||
<img style="max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$user_data.avatar}" alt=" " />
|
||||
<img style="max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$user_data.avatar}" alt=" " />
|
||||
{else}
|
||||
<img src="http://www.gravatar.com/avatar/{$member.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||
{/if}
|
||||
|
55
test/IDF/Scm/SvnTest.php
Normal file
55
test/IDF/Scm/SvnTest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero 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 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
class IDF_Scm_SvnTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $proj = null;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->proj = new IDF_Project();
|
||||
$this->proj->id = 1;
|
||||
$this->proj->name = $this->proj->shortname = 'test';
|
||||
$this->proj->create();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->proj->delete();
|
||||
}
|
||||
|
||||
public function createMock($reponame)
|
||||
{
|
||||
$repourl = 'file://'.DATADIR.'/'.__CLASS__.'/'.$reponame;
|
||||
$instance = new IDF_Scm_Svn($repourl, $this->proj);
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function testAccessHistoryOfRenamedAndDeletedFiles()
|
||||
{
|
||||
$instance = $this->createMock(__FUNCTION__);
|
||||
$this->assertEquals('new-file', $instance->getPathInfo('new-file', 1)->fullpath);
|
||||
$this->assertEquals('alternate-name', $instance->getPathInfo('alternate-name', 2)->fullpath);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
3
|
@@ -0,0 +1,2 @@
|
||||
4
|
||||
layout sharded 1000
|
@@ -0,0 +1 @@
|
||||
fsfs
|
@@ -0,0 +1 @@
|
||||
0
|
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
K 8
|
||||
svn:date
|
||||
V 27
|
||||
2011-08-12T17:06:15.429110Z
|
||||
END
|
@@ -0,0 +1,13 @@
|
||||
K 10
|
||||
svn:author
|
||||
V 7
|
||||
patrick
|
||||
K 8
|
||||
svn:date
|
||||
V 27
|
||||
2011-08-12T17:07:33.111035Z
|
||||
K 7
|
||||
svn:log
|
||||
V 12
|
||||
added a file
|
||||
END
|
@@ -0,0 +1,13 @@
|
||||
K 10
|
||||
svn:author
|
||||
V 7
|
||||
patrick
|
||||
K 8
|
||||
svn:date
|
||||
V 27
|
||||
2011-08-12T17:07:55.894416Z
|
||||
K 7
|
||||
svn:log
|
||||
V 14
|
||||
renamed a file
|
||||
END
|
@@ -0,0 +1,13 @@
|
||||
K 10
|
||||
svn:author
|
||||
V 7
|
||||
patrick
|
||||
K 8
|
||||
svn:date
|
||||
V 27
|
||||
2011-08-12T17:08:12.646051Z
|
||||
K 7
|
||||
svn:log
|
||||
V 14
|
||||
deleted a file
|
||||
END
|
@@ -0,0 +1,11 @@
|
||||
PLAIN
|
||||
END
|
||||
ENDREP
|
||||
id: 0.0.r0/17
|
||||
type: dir
|
||||
count: 0
|
||||
text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e
|
||||
cpath: /
|
||||
|
||||
|
||||
17 107
|
@@ -0,0 +1,28 @@
|
||||
DELTA
|
||||
SVNENDREP
|
||||
id: 0-1.0.r1/17
|
||||
type: file
|
||||
count: 0
|
||||
text: 1 0 4 0 d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0-0/_2
|
||||
cpath: /new-file
|
||||
copyroot: 0 /
|
||||
|
||||
PLAIN
|
||||
K 8
|
||||
new-file
|
||||
V 16
|
||||
file 0-1.0.r1/17
|
||||
END
|
||||
ENDREP
|
||||
id: 0.0.r1/232
|
||||
type: dir
|
||||
pred: 0.0.r0/17
|
||||
count: 1
|
||||
text: 1 180 39 39 4a0c4e617d69f8a0bf11161d1e1b09a6
|
||||
cpath: /
|
||||
copyroot: 0 /
|
||||
|
||||
_0.0.t0-0 add-file true false /new-file
|
||||
|
||||
|
||||
232 357
|
@@ -0,0 +1,29 @@
|
||||
id: 0-1.0-2.r2/0
|
||||
type: file
|
||||
pred: 0-1.0.r1/17
|
||||
count: 1
|
||||
text: 1 0 4 0 d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0-0/_2
|
||||
cpath: /alternate-name
|
||||
copyfrom: 1 /new-file
|
||||
|
||||
PLAIN
|
||||
K 14
|
||||
alternate-name
|
||||
V 17
|
||||
file 0-1.0-2.r2/0
|
||||
END
|
||||
ENDREP
|
||||
id: 0.0.r2/256
|
||||
type: dir
|
||||
pred: 0.0.r1/232
|
||||
count: 2
|
||||
text: 2 196 47 47 518568bcb7e6fe3165235a9f9993f5e1
|
||||
cpath: /
|
||||
copyroot: 0 /
|
||||
|
||||
0-1.0.r1/17 delete-file false false /new-file
|
||||
|
||||
0-1._0.t1-1 add-file false false /alternate-name
|
||||
1 /new-file
|
||||
|
||||
256 382
|
@@ -0,0 +1,15 @@
|
||||
PLAIN
|
||||
END
|
||||
ENDREP
|
||||
id: 0.0.r3/17
|
||||
type: dir
|
||||
pred: 0.0.r2/256
|
||||
count: 3
|
||||
text: 3 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e
|
||||
cpath: /
|
||||
copyroot: 0 /
|
||||
|
||||
0-1.0-2.r2/0 delete-file false false /alternate-name
|
||||
|
||||
|
||||
17 138
|
@@ -0,0 +1 @@
|
||||
3
|
@@ -0,0 +1 @@
|
||||
5d5eaf70-0fe3-4d07-ada0-45c336a5bfad
|
@@ -0,0 +1 @@
|
||||
5
|
Reference in New Issue
Block a user