.gitignore 0000664 0000000 0000000 00000000365 15161610567 0013062 0 ustar 00root root 0000000 0000000 cache/
vendor/
*.diff
*.err
*.orig
*.log
*.rej
*.swo
*.swp
*.zip
*.vi
*~
*.sass-cache
.DS_Store
._*
Thumbs.db
.cache
.project
.settings
.tmproj
*.esproj
nbproject
*.sublime-project
*.sublime-workspace
.hg
.svn
.CVS
.idea
node_modules
config.ini
.htaccess 0000664 0000000 0000000 00000000336 15161610567 0012666 0 ustar 00root root 0000000 0000000
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
order allow,deny
deny from all
.travis.yml 0000664 0000000 0000000 00000000063 15161610567 0013176 0 ustar 00root root 0000000 0000000 language: php
php:
- 5.3
- 5.4
script: phpunit
LICENSE.txt 0000664 0000000 0000000 00000002705 15161610567 0012715 0 ustar 00root root 0000000 0000000 Copyright (c) 2012, Klaus Silveira and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of GitList nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md 0000664 0000000 0000000 00000006634 15161610567 0012356 0 ustar 00root root 0000000 0000000 # GitList: an elegant and modern git repository viewer
[](http://travis-ci.org/klaussilveira/gitlist)
GitList is an elegant and modern web interface for interacting with multiple git repositories. It allows you to browse repositories using your favorite browser, viewing files under different revisions, commit history, diffs. It also generates RSS feeds for each repository, allowing you to stay up-to-date with the latest changes anytime, anywhere. GitList was written in PHP, on top of the [Silex](http://silex.sensiolabs.org/) microframework and powered by the Twig template engine. This means that GitList is easy to install and easy to customize. Also, the GitList gorgeous interface was made possible due to [Bootstrap](http://twitter.github.com/bootstrap/).
## Features
* Multiple repository support
* Multiple branch support
* Multiple tag support
* Commit history, blame, diff
* RSS feeds
* Syntax highlighting
* Repository statistics
## Screenshots
[](http://cloud.github.com/downloads/klaussilveira/gitlist/1.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/2.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/3.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/4.jpg)
[](http://cloud.github.com/downloads/klaussilveira/gitlist/5.jpg)
You can also see a live demo [here](http://git.gofedora.com).
## Authors and contributors
* [Klaus Silveira](http://www.klaussilveira.com) (Creator, developer)
## License
[New BSD license](http://www.opensource.org/licenses/bsd-license.php)
## Todo
* improve the current test code coverage
* test the interface
* error handling can be greatly improved during parsing
* submodule support
* multilanguage support
## Requirements
In order to run GitList on your server, you'll need:
* git
* Apache and mod_rewrite enabled
* PHP 5.3.3
## Installing
Download the GitList latest package and decompress to your `/var/www/gitlist` folder, or anywhere else you want to place GitList. You can also clone the repository:
```
git clone https://github.com/klaussilveira/gitlist.git /var/www/gitlist
```
Rename the `config.ini-example` file to `config.ini`. Now open up the `config.ini` and configure your installation. You'll have to provide where your repositories are located and the base GitList URL (in our case, http://localhost/gitlist). Now, let's create the cache folder and give the correct permissions:
```
cd /var/www/gitlist
mkdir cache
chmod 777 cache
```
That's it, installation complete! If you're having problems, check this [tutorial](http://gofedora.com/insanely-awesome-web-interface-git-repos/) by Kulbir Saini or the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page.
## Further information
If you want to know more about customizing GitList, check the [Customization](https://github.com/klaussilveira/gitlist/wiki/Customizing) page on the wiki. Also, if you're having problems with GitList, check the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page. Don't forget to report issues and suggest new features! :)
composer.json 0000664 0000000 0000000 00000000317 15161610567 0013611 0 ustar 00root root 0000000 0000000 {
"require": {
"silex/silex": "1.0.*",
"twig/twig": "1.8.*"
},
"autoload": {
"psr-0": {
"Application": "lib/",
"Git": "lib/"
}
}
}
composer.lock 0000664 0000000 0000000 00000006061 15161610567 0013572 0 ustar 00root root 0000000 0000000 {
"hash": "3a86b6a3e837b125e3cebc503fd8cf38",
"packages": [
{
"package": "pimple/pimple",
"version": "dev-master",
"alias-pretty-version": "1.0.x-dev",
"alias-version": "1.0.9999999.9999999-dev"
},
{
"package": "pimple/pimple",
"version": "dev-master",
"source-reference": "d2cfa2f02f50abef65c238747c753a5f6786f6be",
"commit-date": "1341139100"
},
{
"package": "silex/silex",
"version": "dev-master",
"alias-pretty-version": "1.0.x-dev",
"alias-version": "1.0.9999999.9999999-dev"
},
{
"package": "silex/silex",
"version": "dev-master",
"source-reference": "13eb2ba916e39d5b8b1d054aaa441cf8e1004d85",
"commit-date": "1341343086"
},
{
"package": "symfony/event-dispatcher",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/event-dispatcher",
"version": "dev-master",
"source-reference": "v2.1.0-BETA1",
"commit-date": "1338018513"
},
{
"package": "symfony/http-foundation",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/http-foundation",
"version": "dev-master",
"source-reference": "3e53f0a9f802dc1f34a722109df0b0d2679671a8",
"commit-date": "1341379664"
},
{
"package": "symfony/http-kernel",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/http-kernel",
"version": "dev-master",
"source-reference": "6d6f55f6b07b8bfed741a192def8d1bfbf6c590f",
"commit-date": "1341332120"
},
{
"package": "symfony/routing",
"version": "dev-master",
"alias-pretty-version": "2.1.x-dev",
"alias-version": "2.1.9999999.9999999-dev"
},
{
"package": "symfony/routing",
"version": "dev-master",
"source-reference": "622a168a3be54a87e34ad65e9d50a738fb89ff7e",
"commit-date": "1341312726"
},
{
"package": "twig/twig",
"version": "dev-master",
"alias-pretty-version": "1.8.x-dev",
"alias-version": "1.8.9999999.9999999-dev"
},
{
"package": "twig/twig",
"version": "dev-master",
"source-reference": "73da773aaad0f97f2e967ec8241b8adf7b1e03d2",
"commit-date": "1340890758"
}
],
"packages-dev": null,
"aliases": [
],
"minimum-stability": "dev",
"stability-flags": [
]
}
config.ini-example 0000664 0000000 0000000 00000000703 15161610567 0014465 0 ustar 00root root 0000000 0000000 [git]
client = '/usr/bin/git' ; Your git executable path
repositories = '/var/www/projects/' ; Path to your repositories
; You can hide repositories from GitList, just copy this for each repository you want to hide
; hidden[] = '/var/www/projects/BetaTest'
[app]
baseurl = 'http://localhost/git' ; Base URL of the application
; If you need to specify custom filetypes for certain extensions, do this here
[filetypes]
; extension = type
; dist = xml controllers/ 0000775 0000000 0000000 00000000000 15161610567 0013434 5 ustar 00root root 0000000 0000000 controllers/blobController.php 0000664 0000000 0000000 00000002477 15161610567 0017141 0 ustar 00root root 0000000 0000000 get('{repo}/blob/{branch}/{file}/', function($repo, $branch, $file) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blob = $repository->getBlob("$branch:'$file'");
$breadcrumbs = $app['utils']->getBreadcrumbs("$repo/tree/$branch/$file");
$fileType = $app['utils']->getFileType($file);
return $app['twig']->render('file.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'files',
'file' => $file,
'fileType' => $fileType,
'blob' => $blob->output(),
'repo' => $repo,
'branch' => $branch,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('file', '.+')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+');
$app->get('{repo}/raw/{branch}/{file}', function($repo, $branch, $file) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blob = $repository->getBlob("$branch:'$file'")->output();
return new Symfony\Component\HttpFoundation\Response($blob, 200, array('Content-Type' => 'text/plain'));
})->assert('file', '.+')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+');
controllers/commitController.php 0000664 0000000 0000000 00000006227 15161610567 0017510 0 ustar 00root root 0000000 0000000 get('{repo}/commits/{branch}', function($repo, $branch) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$pager = $app['utils']->getPager($app['request']->get('page'), $repository->getTotalCommits());
$commits = $repository->getCommits($branch, $pager['current']);
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
return $app['twig']->render('commits.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'commits',
'pager' => $pager,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'commits' => $categorized,
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->value('branch', 'master');
$app->get('{repo}/commits/{branch}/{file}/', function($repo, $branch, $file) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$pager = $app['utils']->getPager($app['request']->get('page'), $repository->getTotalCommits("$branch -- $file"));
$commits = $repository->getCommits("$branch -- $file", $pager['current']);
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
return $app['twig']->render('commits.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'commits',
'pager' => $pager,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'commits' => $categorized,
));
})->assert('repo', '[\w-._]+')
->assert('file', '.+')
->assert('branch', '[\w-._]+');
$app->get('{repo}/commit/{commit}/', function($repo, $commit) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commit = $repository->getCommit($commit);
return $app['twig']->render('commit.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'commits',
'branch' => 'master',
'repo' => $repo,
'commit' => $commit,
));
})->assert('repo', '[\w-._]+')
->assert('commit', '[a-f0-9]+');
$app->get('{repo}/blame/{branch}/{file}/', function($repo, $branch, $file) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$blames = $repository->getBlame("$branch -- $file");
return $app['twig']->render('blame.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'commits',
'file' => $file,
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'blames' => $blames,
));
})->assert('repo', '[\w-._]+')
->assert('file', '.+')
->assert('branch', '[\w-._]+');
controllers/indexController.php 0000664 0000000 0000000 00000000413 15161610567 0017316 0 ustar 00root root 0000000 0000000 get('/', function() use($app) {
$repositories = $app['git']->getRepositories($app['git.repos']);
return $app['twig']->render('index.twig', array(
'baseurl' => $app['baseurl'],
'repositories' => $repositories,
));
}); controllers/rssController.php 0000664 0000000 0000000 00000001127 15161610567 0017021 0 ustar 00root root 0000000 0000000 get('{repo}/{branch}/rss/', function($repo, $branch) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commits = $repository->getCommits($branch);
$html = $app['twig']->render('rss.twig', array(
'baseurl' => $app['baseurl'],
'repo' => $repo,
'branch' => $branch,
'commits' => $commits,
));
return new Symfony\Component\HttpFoundation\Response($html, 200, array('Content-Type' => 'application/rss+xml'));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+'); controllers/statsController.php 0000664 0000000 0000000 00000001352 15161610567 0017350 0 ustar 00root root 0000000 0000000 get('{repo}/stats/{branch}', function($repo, $branch) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$stats = $repository->getStatistics($branch);
$authors = $repository->getAuthorStatistics();
return $app['twig']->render('stats.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'stats',
'repo' => $repo,
'branch' => $branch,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'stats' => $stats,
'authors' => $authors,
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->value('branch', 'master'); controllers/treeController.php 0000664 0000000 0000000 00000005272 15161610567 0017156 0 ustar 00root root 0000000 0000000 get('{repo}/', function($repo) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$defaultBranch = $repository->getHead();
$tree = $repository->getTree($defaultBranch);
$breadcrumbs = $app['utils']->getBreadcrumbs("$repo/");
return $app['twig']->render('tree.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'files',
'files' => $tree->output(),
'repo' => $repo,
'branch' => $defaultBranch,
'path' => '',
'parent' => '',
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'readme' => $app['utils']->getReadme($repo, $defaultBranch),
));
})->assert('repo', '[\w-._]+');
$app->get('{repo}/tree/{branch}/', function($repo, $branch) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$tree = $repository->getTree($branch);
$breadcrumbs = $app['utils']->getBreadcrumbs("$repo/");
return $app['twig']->render('tree.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'files',
'files' => $tree->output(),
'repo' => $repo,
'branch' => $branch,
'path' => '',
'parent' => '',
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
'readme' => $app['utils']->getReadme($repo, $branch),
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+');
$app->get('{repo}/tree/{branch}/{tree}/', function($repo, $branch, $tree) use($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$files = $repository->getTree("$branch:'$tree'/");
$breadcrumbs = $app['utils']->getBreadcrumbs("$repo/tree/$branch/$tree");
if (($slash = strrpos($tree, '/')) !== false) {
$parent = '/' . substr($tree, 0, $slash);
} else {
$parent = '/';
}
return $app['twig']->render('tree.twig', array(
'baseurl' => $app['baseurl'],
'page' => 'files',
'files' => $files->output(),
'repo' => $repo,
'branch' => $branch,
'path' => "$tree/",
'parent' => $parent,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('tree', '.+')
->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+');
index.php 0000664 0000000 0000000 00000003277 15161610567 0012717 0 ustar 00root root 0000000 0000000 register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/views',
'twig.options' => array('cache' => __DIR__.'/cache'),
));
$app->register(new Git\GitServiceProvider(), array(
'git.client' => $config['git']['client'],
'git.repos' => $config['git']['repositories'],
));
$app->register(new Application\UtilsServiceProvider());
// Add the md5() function to Twig scope
$app['twig']->addFilter('md5', new Twig_Filter_Function('md5'));
// Load controllers
include 'controllers/indexController.php';
include 'controllers/treeController.php';
include 'controllers/blobController.php';
include 'controllers/commitController.php';
include 'controllers/statsController.php';
include 'controllers/rssController.php';
// Error handling
$app->error(function (\Exception $e, $code) use ($app) {
return $app['twig']->render('error.twig', array(
'baseurl' => $app['baseurl'],
'message' => $e->getMessage(),
));
});
$app->run();
lib/ 0000775 0000000 0000000 00000000000 15161610567 0011634 5 ustar 00root root 0000000 0000000 lib/Application/ 0000775 0000000 0000000 00000000000 15161610567 0014077 5 ustar 00root root 0000000 0000000 lib/Application/Utils.php 0000664 0000000 0000000 00000016355 15161610567 0015722 0 ustar 00root root 0000000 0000000 app = $app;
}
/**
* Builds a breadcrumb array based on a path spec
*
* @param string $spec Path spec
* @return array Array with parts of the breadcrumb
*/
public function getBreadcrumbs($spec)
{
$paths = explode('/', $spec);
$last = '';
foreach ($paths as $path) {
$dir['dir'] = $path;
$dir['path'] = "$last/$path";
$breadcrumbs[] = $dir;
$last .= '/' . $path;
}
if (isset($paths[2])) {
$breadcrumbs[0]['path'] .= '/' . $paths[1] . '/' . $paths[2];
}
unset($breadcrumbs[1], $breadcrumbs[2]);
return $breadcrumbs;
}
/**
* Returns the file type based on filename by treating the extension
*
* The file type is used by CodeMirror, a Javascript-based IDE implemented in
* GitList, to properly highlight the blob syntax (if it's a source-code)
*
* @param string $spec File name
* @return string File type
*/
public function getFileType($file)
{
if (($pos = strrpos($file, '.')) !== FALSE) {
$fileType = substr($file, $pos + 1);
} else {
return 'text';
}
switch ($fileType) {
case 'php':
return 'php';
case 'c':
return 'clike';
case 'h':
return 'clike';
case 'cpp':
return 'clike';
case 'cs':
return 'csharp';
case 'm':
return 'clike';
case 'mm':
return 'clike';
case 'java':
return 'java';
case 'clj':
return 'clojure';
case 'coffee':
return 'coffeescript';
case 'css':
return 'css';
case 'diff':
return 'diff';
case 'ecl':
return 'ecl';
case 'el':
return 'erlang';
case 'go':
return 'go';
case 'groovy':
return 'groovy';
case 'hs':
return 'haskell';
case 'lhs':
return 'haskell';
case 'jsp':
return 'htmlembedded';
case 'asp':
return 'htmlembedded';
case 'aspx':
return 'htmlembedded';
case 'html':
return 'htmlmixed';
case 'tpl':
return 'htmlmixed';
case 'js':
return 'javascript';
case 'json':
return 'javascript';
case 'less':
return 'less';
case 'lua':
return 'lua';
case 'md':
return 'markdown';
case 'markdown':
return 'markdown';
case 'sql':
return 'mysql';
case 'pl':
return 'perl';
case 'pm':
return 'perl';
case 'pas':
return 'pascal';
case 'ini':
return 'properties';
case 'cfg':
return 'properties';
case 'nt':
return 'ntriples';
case 'py':
return 'python';
case 'rb':
return 'ruby';
case 'rst':
return 'rst';
case 'r':
return 'r';
case 'sh':
return 'shell';
case 'ss':
return 'scheme';
case 'scm':
return 'scheme';
case 'sls':
return 'scheme';
case 'sps':
return 'scheme';
case 'rs':
return 'rust';
case 'st':
return 'smalltalk';
case 'tex':
return 'stex';
case 'vbs':
return 'vbscript';
case 'v':
return 'verilog';
case 'xml':
return 'xml';
case 'xsd':
return 'xml';
case 'xsl':
return 'xml';
case 'xul':
return 'xml';
case 'xlf':
return 'xml';
case 'xliff':
return 'xml';
case 'xaml':
return 'xml';
case 'wxs':
return 'xml';
case 'wxl':
return 'xml';
case 'wxi':
return 'xml';
case 'wsdl':
return 'xml';
case 'svg':
return 'xml';
case 'rss':
return 'xml';
case 'rdf':
return 'xml';
case 'plist':
return 'xml';
case 'mxml':
return 'xml';
case 'kml':
return 'xml';
case 'glade':
return 'xml';
case 'xq':
return 'xquery';
case 'xqm':
return 'xquery';
case 'xquery':
return 'xquery';
case 'xqy':
return 'xquery';
case 'yml':
return 'yaml';
case 'yaml':
return 'yaml';
case 'png':
return 'image';
case 'jpg':
return 'image';
case 'gif':
return 'image';
case 'jpeg':
return 'image';
case 'bmp':
return 'image';
}
if (!empty($this->app['filetypes'])) {
foreach ($this->app['filetypes'] as $ext => $type) {
if ($fileType == $ext) {
return $type;
}
}
}
}
public function getPager($pageNumber, $totalCommits)
{
$pageNumber = (empty($pageNumber)) ? 0 : $pageNumber;
$lastPage = intval($totalCommits / 15);
// If total commits are integral multiple of 15, the lastPage will be commits/15 - 1.
$lastPage = ($lastPage * 15 == $totalCommits) ? $lastPage - 1 : $lastPage;
$nextPage = $pageNumber + 1;
$previousPage = $pageNumber - 1;
return array('current' => $pageNumber,
'next' => $nextPage,
'previous' => $previousPage,
'last' => $lastPage,
'total' => $totalCommits,
);
}
public function getReadme($repo, $branch = 'master')
{
$repository = $this->app['git']->getRepository($this->app['git.repos'] . $repo);
$files = $repository->getTree($branch)->output();
foreach ($files as $fileInfo)
if (preg_match('/^readme*/i', $fileInfo['name'])) {
return array('filename' => $fileInfo['name'], 'content' => $repository->getBlob("$branch:'".$fileInfo['name']."'")->output());
}
return array();
}
}
lib/Application/UtilsServiceProvider.php 0000664 0000000 0000000 00000001055 15161610567 0020745 0 ustar 00root root 0000000 0000000 app = $app;
$path = $this->app['git.client'] ? $this->app['git.client'] : '/usr/bin/git';
$this->setPath($path);
}
/**
* Creates a new repository on the specified path
*
* @param string $path Path where the new repository will be created
* @return Repository Instance of Repository
*/
public function createRepository($path)
{
if (file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) {
throw new \RuntimeException('A GIT repository already exists at ' . $path);
}
$repository = new Repository($path, $this);
return $repository->create();
}
/**
* Opens a repository at the specified path
*
* @param string $path Path where the repository is located
* @return Repository Instance of Repository
*/
public function getRepository($path)
{
if (!file_exists($path) || !file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) {
throw new \RuntimeException('There is no GIT repository at ' . $path);
}
if (in_array($path, $this->app['hidden'])) {
throw new \RuntimeException('You don\'t have access to this repository');
}
return new Repository($path, $this);
}
/**
* Searches for valid repositories on the specified path
*
* @param string $path Path where repositories will be searched
* @return array Found repositories, containing their name, path and description
*/
public function getRepositories($path)
{
$repositories = $this->recurseDirectory($path);
if (empty($repositories)) {
throw new \RuntimeException('There are no GIT repositories in ' . $path);
}
sort($repositories);
return $repositories;
}
private function recurseDirectory($path)
{
$dir = new \DirectoryIterator($path);
$repositories = array();
foreach ($dir as $file) {
if ($file->isDot()) {
continue;
}
if (($pos = strrpos($file->getFilename(), '.')) === 0) {
continue;
}
$isBare = file_exists($file->getPathname() . '/HEAD');
$isRepository = file_exists($file->getPathname() . '/.git/HEAD');
if ($file->isDir() && $isRepository || $isBare) {
if (in_array($file->getPathname(), $this->app['hidden'])) {
continue;
}
if ($isBare) {
$description = $file->getPathname() . '/description';
} else {
$description = $file->getPathname() . '/.git/description';
}
if (file_exists($description)) {
$description = file_get_contents($description);
} else {
$description = 'There is no repository description file. Please, create one to remove this message.';
}
$repositories[] = array('name' => $file->getFilename(), 'path' => $file->getPathname(), 'description' => $description);
continue;
}
}
return $repositories;
}
/**
* Execute a git command on the repository being manipulated
*
* This method will start a new process on the current machine and
* run git commands. Once the command has been run, the method will
* return the command line output.
*
* @param Repository $repository Repository where the command will be run
* @param string $command Git command to be run
* @return string Returns the command output
*/
public function run(Repository $repository, $command)
{
$descriptors = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
$process = proc_open($this->getPath() . ' ' . $command, $descriptors, $pipes, $repository->getPath());
if (!is_resource($process)) {
throw new \RuntimeException('Unable to execute command: ' . $command);
}
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
if (!empty($stderr)) {
throw new \RuntimeException($stderr);
}
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($process);
return $stdout;
}
/**
* Get the current Git binary path
*
* @return string Path where the Git binary is located
*/
protected function getPath()
{
return $this->path;
}
/**
* Set the current Git binary path
*
* @param string $path Path where the Git binary is located
*/
protected function setPath($path)
{
$this->path = $path;
}
}
lib/Git/Commit/ 0000775 0000000 0000000 00000000000 15161610567 0013607 5 ustar 00root root 0000000 0000000 lib/Git/Commit/Author.php 0000664 0000000 0000000 00000001003 15161610567 0015554 0 ustar 00root root 0000000 0000000 setName($name);
$this->setEmail($email);
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
}
} lib/Git/Commit/Commit.php 0000664 0000000 0000000 00000005250 15161610567 0015552 0 ustar 00root root 0000000 0000000 setHash($data['hash']);
$this->setShortHash($data['short_hash']);
$this->setTreeHash($data['tree']);
$this->setParentHash($data['parent']);
$this->setAuthor(
new Author($data['author'], $data['author_email'])
);
$this->setDate(
new \DateTime('@' . $data['date'])
);
$this->setCommiter(
new Author($data['commiter'], $data['commiter_email'])
);
$this->setCommiterDate(
new \DateTime('@' . $data['commiter_date'])
);
$this->setMessage($data['message']);
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getShortHash()
{
return $this->shortHash;
}
public function setShortHash($shortHash)
{
$this->shortHash = $shortHash;
}
public function getTreeHash()
{
return $this->treeHash;
}
public function setTreeHash($treeHash)
{
$this->treeHash = $treeHash;
}
public function getParentHash()
{
return $this->parentHash;
}
public function setParentHash($parentHash)
{
$this->parentHash = $parentHash;
}
public function getAuthor()
{
return $this->author;
}
public function setAuthor($author)
{
$this->author = $author;
}
public function getDate()
{
return $this->date;
}
public function setDate($date)
{
$this->date = $date;
}
public function getCommiter()
{
return $this->commiter;
}
public function setCommiter($commiter)
{
$this->commiter = $commiter;
}
public function getCommiterDate()
{
return $this->commiterDate;
}
public function setCommiterDate($commiterDate)
{
$this->commiterDate = $commiterDate;
}
public function getMessage()
{
return $this->message;
}
public function setMessage($message)
{
$this->message = $message;
}
public function getDiffs()
{
return $this->diffs;
}
public function setDiffs($diffs)
{
$this->diffs = $diffs;
}
public function getChangedFiles()
{
return sizeof($this->diffs);
}
} lib/Git/GitServiceProvider.php 0000664 0000000 0000000 00000001045 15161610567 0016647 0 ustar 00root root 0000000 0000000 setClient($client);
$this->setRepository($repository);
$this->setHash($hash);
}
public function output()
{
$data = $this->getClient()->run($this->getRepository(), 'show ' . $this->getHash());
return $data;
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getSize()
{
return $this->size;
}
public function setSize($size)
{
$this->size = $size;
}
} lib/Git/Model/Diff.php 0000664 0000000 0000000 00000001626 15161610567 0015005 0 ustar 00root root 0000000 0000000 lines[] = new Line($line);
}
public function getLines()
{
return $this->lines;
}
public function setIndex($index)
{
$this->index = $index;
}
public function getIndex()
{
return $this->index;
}
public function setOld($old)
{
$this->old = $old;
}
public function getOld()
{
return $this->old;
}
public function setNew($new)
{
$this->new = $new;
}
public function getNew()
{
return $this->new;
}
public function setFile($file)
{
$this->file = $file;
}
public function getFile()
{
return $this->file;
}
} lib/Git/Model/Line.php 0000664 0000000 0000000 00000001404 15161610567 0015016 0 ustar 00root root 0000000 0000000 setType('chunk');
}
if ($data[0] == '-') {
$this->setType('old');
}
if ($data[0] == '+') {
$this->setType('new');
}
}
$this->setLine($data);
}
public function getLine()
{
return $this->line;
}
public function setLine($line)
{
$this->line = $line;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
} lib/Git/Model/Symlink.php 0000664 0000000 0000000 00000001142 15161610567 0015554 0 ustar 00root root 0000000 0000000 mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getPath()
{
return $this->path;
}
public function setPath($path)
{
$this->path = $path;
}
} lib/Git/Model/Tree.php 0000664 0000000 0000000 00000010404 15161610567 0015026 0 ustar 00root root 0000000 0000000 setClient($client);
$this->setRepository($repository);
$this->setHash($hash);
}
public function parse()
{
$data = $this->getClient()->run($this->getRepository(), 'ls-tree -l ' . $this->getHash());
$lines = explode("\n", $data);
$files = array();
$root = array();
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line, 5);
}
foreach ($files as $file) {
if ($file[1] == 'commit') {
// submodule
continue;
}
if ($file[0] == '120000') {
$show = $this->getClient()->run($this->getRepository(), 'show ' . $file[2]);
$tree = new Symlink;
$tree->setMode($file[0]);
$tree->setName($file[4]);
$tree->setPath($show);
$root[] = $tree;
continue;
}
if ($file[1] == 'blob') {
$blob = new Blob($file[2], $this->getClient(), $this->getRepository());
$blob->setMode($file[0]);
$blob->setName($file[4]);
$blob->setSize($file[3]);
$root[] = $blob;
continue;
}
$tree = new Tree($file[2], $this->getClient(), $this->getRepository());
$tree->setMode($file[0]);
$tree->setName($file[4]);
$root[] = $tree;
}
$this->data = $root;
}
public function output()
{
$files = $folders = array();
foreach ($this as $node) {
if ($node instanceof Blob) {
$file['type'] = 'blob';
$file['name'] = $node->getName();
$file['size'] = $node->getSize();
$file['mode'] = $node->getMode();
$file['hash'] = $node->getHash();
$files[] = $file;
continue;
}
if ($node instanceof Tree) {
$folder['type'] = 'folder';
$folder['name'] = $node->getName();
$folder['size'] = '';
$folder['mode'] = $node->getMode();
$folder['hash'] = $node->getHash();
$folders[] = $folder;
continue;
}
if ($node instanceof Symlink) {
$folder['type'] = 'symlink';
$folder['name'] = $node->getName();
$folder['size'] = '';
$folder['mode'] = $node->getMode();
$folder['hash'] = '';
$folder['path'] = $node->getPath();
$folders[] = $folder;
}
}
// Little hack to make folders appear before files
$files = array_merge($folders, $files);
return $files;
}
public function valid() {
return isset($this->data[$this->position]);
}
public function hasChildren() {
return is_array($this->data[$this->position]);
}
public function next() {
$this->position++;
}
public function current() {
return $this->data[$this->position];
}
public function getChildren() {
return $this->data[$this->position];
}
public function rewind() {
$this->position = 0;
}
public function key() {
return $this->position;
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getHash()
{
return $this->hash;
}
public function setHash($hash)
{
$this->hash = $hash;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
lib/Git/Repository.php 0000664 0000000 0000000 00000033560 15161610567 0015256 0 ustar 00root root 0000000 0000000 setPath($path);
$this->setClient($client);
}
public function setClient(Client $client)
{
$this->client = $client;
}
public function getClient()
{
return $this->client;
}
public function create()
{
mkdir($this->getPath());
$this->getClient()->run($this, 'init');
return $this;
}
public function getConfig($key)
{
$key = $this->getClient()->run($this, 'config ' . $key);
return trim($key);
}
public function setConfig($key, $value)
{
$this->getClient()->run($this, "config $key \"$value\"");
return $this;
}
/**
* Add untracked files
*
* @access public
* @param mixed $files Files to be added to the repository
*/
public function add($files = '.')
{
if(is_array($files)) {
$files = implode(' ', $files);
}
$this->getClient()->run($this, "add $files");
return $this;
}
/**
* Add all untracked files
*
* @access public
*/
public function addAll()
{
$this->getClient()->run($this, "add -A");
return $this;
}
/**
* Commit changes to the repository
*
* @access public
* @param string $message Description of the changes made
*/
public function commit($message)
{
$this->getClient()->run($this, "commit -m '$message'");
return $this;
}
/**
* Checkout a branch
*
* @access public
* @param string $branch Branch to be checked out
*/
public function checkout($branch)
{
$this->getClient()->run($this, "checkout $branch");
return $this;
}
/**
* Pull repository changes
*
* @access public
*/
public function pull()
{
$this->getClient()->run($this, "pull");
return $this;
}
/**
* Update remote references
*
* @access public
* @param string $repository Repository to be pushed
* @param string $refspec Refspec for the push
*/
public function push($repository = null, $refspec = null)
{
$command = "push";
if($repository) {
$command .= " $repository";
}
if($refspec) {
$command .= " $refspec";
}
$this->getClient()->run($this, $command);
return $this;
}
/**
* Show a list of the repository branches
*
* @access public
* @return array List of branches
*/
public function getBranches()
{
$branches = $this->getClient()->run($this, "branch");
$branches = explode("\n", $branches);
$branches = array_filter(preg_replace('/[\*\s]/', '', $branches));
return $branches;
}
/**
* Show the current repository branch
*
* @access public
* @return string Current repository branch
*/
public function getCurrentBranch()
{
$branches = $this->getClient()->run($this, "branch");
$branches = explode("\n", $branches);
foreach($branches as $branch) {
if($branch[0] == '*') {
return substr($branch, 2);
}
}
}
/**
* Check if a specified branch exists
*
* @access public
* @param string $branch Branch to be checked
* @return boolean True if the branch exists
*/
public function hasBranch($branch)
{
$branches = $this->getBranches();
$status = in_array($branch, $branches);
return $status;
}
/**
* Create a new repository branch
*
* @access public
* @param string $branch Branch name
*/
public function createBranch($branch)
{
$this->getClient()->run($this, "branch $branch");
}
/**
* Show a list of the repository tags
*
* @access public
* @return array List of tags
*/
public function getTags()
{
$tags = $this->getClient()->run($this, "tag");
$tags = explode("\n", $tags);
if (empty($tags[0])) {
return NULL;
}
return $tags;
}
/**
* Show the amount of commits on the repository
*
* @access public
* @return integer Total number of commits
*/
public function getTotalCommits($file = null)
{
$command = "rev-list --all";
if ($file) {
$command .= " $file";
}
$command .= " | wc -l";
$commits = $this->getClient()->run($this, $command);
return $commits;
}
/**
* Show the repository commit log
*
* @access public
* @return array Commit log
*/
public function getCommits($file = null, $page = 0)
{
$page = 15 * $page;
$pager = "--skip=$page --max-count=15";
$command = 'log ' . $pager . ' --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\'';
if ($file) {
$command .= " $file";
}
$logs = $this->getClient()->run($this, $command);
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = str_replace("\n", ',', $logs);
$logs = json_decode("{ $logs }", true);
foreach ($logs as $log) {
$log['message'] = str_replace('-', ' ', $log['message']);
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
}
return $commits;
}
public function getRelatedCommits($hash)
{
$logs = $this->getClient()->run($this, 'log --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\'');
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = str_replace("\n", ',', $logs);
$logs = json_decode("{ $logs }", true);
foreach ($logs as $log) {
$log['message'] = str_replace('-', ' ', $log['message']);
$logTree = $this->getClient()->run($this, 'diff-tree -t -r ' . $log['hash']);
$lines = explode("\n", $logTree);
array_shift($lines);
$files = array();
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line);
}
// Now let's find the commits who have our hash within them
foreach ($files as $file) {
if ($file[1] == 'commit') {
continue;
}
if ($file[3] == $hash) {
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
break;
}
}
}
return $commits;
}
public function getCommit($commit)
{
$logs = $this->getClient()->run($this, 'show --pretty=format:\'{"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\' ' . $commit);
if (empty($logs)) {
throw new \RuntimeException('No commit log available');
}
$logs = explode("\n", $logs);
// Read commit metadata
$data = json_decode($logs[0], true);
$data['message'] = str_replace('-', ' ', $data['message']);
$commit = new Commit;
$commit->importData($data);
unset($logs[0]);
if (empty($logs[1])) {
throw new \RuntimeException('No commit log available');
}
// Read diff logs
foreach ($logs as $log) {
if ('diff' === substr($log, 0, 4)) {
if (isset($diff)) {
$diffs[] = $diff;
}
$diff = new Diff;
preg_match('/^diff --[\S]+ (a\/)?([\S]+)( b\/)?/', $log, $name);
$diff->setFile($name[2]);
continue;
}
if ('index' === substr($log, 0, 5)) {
$diff->setIndex($log);
continue;
}
if ('---' === substr($log, 0, 3)) {
$diff->setOld($log);
continue;
}
if ('+++' === substr($log, 0, 3)) {
$diff->setNew($log);
continue;
}
// Handle binary files properly.
if ('Binary' === substr($log, 0, 6)) {
$m = array();
if (preg_match('/Binary files (.+) and (.+) differ/', $log, $m)) {
$diff->setOld($m[1]);
$diff->setNew(" {$m[2]}");
}
}
$diff->addLine($log);
}
if (isset($diff)) {
$diffs[] = $diff;
}
$commit->setDiffs($diffs);
return $commit;
}
public function getAuthorStatistics()
{
$logs = $this->getClient()->run($this, 'log --pretty=format:\'%an||%ae\'');
if (empty($logs)) {
throw new \RuntimeException('No statistics available');
}
$logs = explode("\n", $logs);
$logs = array_count_values($logs);
arsort($logs);
foreach ($logs as $user => $count) {
$user = explode('||', $user);
$data[] = array('name' => $user[0], 'email' => $user[1], 'commits' => $count);
}
return $data;
}
/**
* Get the current HEAD.
*
* @return string the name of the HEAD branch.
*/
public function getHead()
{
if (file_exists($this->getPath() . '/.git/HEAD')) {
$file = @file_get_contents($this->getPath() . '/.git/HEAD');
}
else if (file_exists($this->getPath() . '/HEAD')) {
$file = @file_get_contents($this->getPath() . '/HEAD');
}
else {
return 'master';
}
foreach (explode("\n", $file) as $line) {
$m = array();
if (preg_match('#ref:\srefs/heads/(.+)#', $line, $m)) {
return $m[1];
}
}
// Default to something sane if in a detached HEAD state.
return 'master';
}
public function getStatistics($branch)
{
// Calculate amount of files, extensions and file size
$logs = $this->getClient()->run($this, 'ls-tree -r -l ' . $branch);
$lines = explode("\n", $logs);
$files = array();
$data['extensions'] = array();
$data['size'] = 0;
$data['files'] = 0;
foreach ($lines as $key => $line) {
if (empty($line)) {
unset($lines[$key]);
continue;
}
$files[] = preg_split("/[\s]+/", $line);
}
foreach ($files as $file) {
if ($file[1] == 'blob') {
$data['files']++;
}
if (is_numeric($file[3])) {
$data['size'] += $file[3];
}
if (($pos = strrpos($file[4], '.')) !== FALSE) {
$data['extensions'][] = substr($file[4], $pos);
}
}
$data['extensions'] = array_count_values($data['extensions']);
arsort($data['extensions']);
return $data;
}
/**
* Get the Tree for the provided folder
*
* @param string $tree Folder that will be parsed
* @return Tree Instance of Tree for the provided folder
*/
public function getTree($tree)
{
$tree = new Tree($tree, $this->getClient(), $this);
$tree->parse();
return $tree;
}
/**
* Get the Blob for the provided file
*
* @param string $blob File that will be parsed
* @return Blob Instance of Blob for the provided file
*/
public function getBlob($blob)
{
return new Blob($blob, $this->getClient(), $this);
}
/**
* Blames the provided file and parses the output
*
* @param string $file File that will be blamed
* @return array Commits hashes containing the lines
*/
public function getBlame($file)
{
$blame = array();
$logs = $this->getClient()->run($this, "blame -s $file");
$logs = explode("\n", $logs);
$i = 0;
$previous_commit = '';
foreach ($logs as $log) {
if ($log == '') {
continue;
}
preg_match_all("/([a-zA-Z0-9^]{8})[\s]+([0-9]+)\)(.+)/", $log, $match);
$current_commit = $match[1][0];
if ($current_commit != $previous_commit) {
++$i;
$blame[$i] = array('line' => '', 'commit' => $current_commit);
}
$blame[$i]['line'] .= PHP_EOL . $match[3][0];
$previous_commit = $current_commit;
}
return $blame;
}
/**
* Get the current Repository path
*
* @return string Path where the repository is located
*/
public function getPath()
{
return $this->path;
}
/**
* Set the current Repository path
*
* @param string $path Path where the repository is located
*/
public function setPath($path)
{
$this->path = $path;
}
}
lib/Git/ScopeAware.php 0000664 0000000 0000000 00000000674 15161610567 0015130 0 ustar 00root root 0000000 0000000 client = $client;
}
public function getClient()
{
return $this->client;
}
public function getRepository()
{
return $this->repository;
}
public function setRepository($repository)
{
$this->repository = $repository;
}
} nginx/ 0000775 0000000 0000000 00000000000 15161610567 0012211 5 ustar 00root root 0000000 0000000 nginx/server.conf 0000664 0000000 0000000 00000002033 15161610567 0014364 0 ustar 00root root 0000000 0000000 server {
server_name MYSERVER;
access_log /var/log/nginx/MYSERVER.access_log main;
error_log /var/log/nginx/MYSERVER.error_log debug_http;
root /var/www/DIR;
index index.php;
# auth_basic "Restricted";
# auth_basic_user_file rhtpasswd;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~* ^/index.php.*$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi.conf;
}
location / {
try_files $uri @gitlist;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
add_header Vary "Accept-Encoding";
expires max;
try_files $uri @gitlist;
tcp_nodelay off;
tcp_nopush on;
}
# location ~* \.(git|svn|patch|htaccess|log|route|plist|inc|json|pl|po|sh|ini|sample|kdev4)$ {
# deny all;
# }
location @gitlist {
rewrite ^/.*$ /index.php;
}
}
phpunit.xml.dist 0000664 0000000 0000000 00000001003 15161610567 0014233 0 ustar 00root root 0000000 0000000
./tests/
tests/ 0000775 0000000 0000000 00000000000 15161610567 0012230 5 ustar 00root root 0000000 0000000 tests/ClientTest.php 0000664 0000000 0000000 00000036564 15161610567 0015035 0 ustar 00root root 0000000 0000000 markTestSkipped('There are no write permissions in order to create test repositories.');
}
$app = new Silex\Application();
$app['git.client'] = '/usr/bin/git';
$app['hidden'] = array();
$this->client = new Client($app);
}
/**
* @expectedException RuntimeException
*/
public function testIsNotFindingRepositories()
{
$this->client->getRepositories($this->repoPath);
}
/**
* @expectedException RuntimeException
*/
public function testIsNotAbleToGetUnexistingRepository()
{
$this->client->getRepository($this->repoPath);
}
public function testIsCreatingRepository()
{
$repository = $this->client->createRepository($this->repoPath);
$this->assertRegExp("/nothing to commit/", $repository->getClient()->run($repository, 'status'));
}
/**
* @expectedException RuntimeException
*/
public function testIsNotAbleToCreateRepositoryDueToExistingOne()
{
$this->client->createRepository($this->repoPath);
}
public function testIsListingRepositories()
{
$this->client->createRepository($this->repoPath . '/../anothertestrepo');
$this->client->createRepository($this->repoPath . '/../bigbadrepo');
$repositories = $this->client->getRepositories($this->repoPath . '/../');
$this->assertEquals($repositories[0]['name'], 'anothertestrepo');
$this->assertEquals($repositories[1]['name'], 'bigbadrepo');
$this->assertEquals($repositories[2]['name'], 'testrepo');
}
public function testIsConfiguratingRepository()
{
$repository = $this->client->getRepository($this->repoPath);
$repository->setConfig('user.name', 'Luke Skywalker');
$repository->setConfig('user.email', 'luke@republic.com');
$this->assertEquals($repository->getConfig('user.name'), 'Luke Skywalker');
$this->assertEquals($repository->getConfig('user.email'), 'luke@republic.com');
}
/**
* @depends testIsCreatingRepository
*/
public function testIsAdding()
{
$repository = $this->client->getRepository($this->repoPath);
file_put_contents($this->repoPath . '/test_file.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add('test_file.txt');
$this->assertRegExp("/new file: test_file.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAdding
*/
public function testIsAddingDot()
{
$repository = $this->client->getRepository($this->repoPath);
file_put_contents($this->repoPath . '/test_file1.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file2.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file3.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add();
$this->assertRegExp("/new file: test_file1.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file2.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file3.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingDot
*/
public function testIsAddingAll()
{
$repository = $this->client->getRepository($this->repoPath);
file_put_contents($this->repoPath . '/test_file4.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file5.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file6.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->addAll();
$this->assertRegExp("/new file: test_file4.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file5.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file6.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingAll
*/
public function testIsAddingArrayOfFiles()
{
$repository = $this->client->getRepository($this->repoPath);
file_put_contents($this->repoPath . '/test_file7.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file8.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
file_put_contents($this->repoPath . '/test_file9.txt', 'Your mother is so ugly, glCullFace always returns TRUE.');
$repository->add(array('test_file7.txt', 'test_file8.txt', 'test_file9.txt'));
$this->assertRegExp("/new file: test_file7.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file8.txt/", $repository->getClient()->run($repository, 'status'));
$this->assertRegExp("/new file: test_file9.txt/", $repository->getClient()->run($repository, 'status'));
}
/**
* @depends testIsAddingArrayOfFiles
*/
public function testIsCommiting()
{
$repository = $this->client->getRepository($this->repoPath);
$repository->commit("The truth unveiled");
$this->assertRegExp("/The truth unveiled/", $repository->getClient()->run($repository, 'log'));
}
public function testIsCreatingBranches()
{
$repository = $this->client->getRepository($this->repoPath);
$repository->createBranch('issue12');
$repository->createBranch('issue42');
$branches = $repository->getBranches();
$this->assertContains('issue12', $branches);
$this->assertContains('issue42', $branches);
$this->assertContains('master', $branches);
}
public function testIsGettingCurrentBranch()
{
$repository = $this->client->getRepository($this->repoPath);
$branch = $repository->getCurrentBranch();
$this->assertTrue($branch === 'master');
}
/**
* @depends testIsCommiting
*/
public function testIsGettingCommits()
{
$repository = $this->client->getRepository($this->repoPath);
$commits = $repository->getCommits();
foreach ($commits as $commit) {
$this->assertInstanceOf('Git\Commit\Commit', $commit);
$this->assertTrue($commit->getMessage() === 'The truth unveiled');
$this->assertInstanceOf('Git\Commit\Author', $commit->getAuthor());
$this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getAuthor()->getEmail(), 'luke@republic.com');
$this->assertEquals($commit->getCommiter()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getCommiter()->getEmail(), 'luke@republic.com');
$this->assertEquals($commit->getParentHash(), '');
$this->assertInstanceOf('DateTime', $commit->getDate());
$this->assertInstanceOf('DateTime', $commit->getCommiterDate());
$this->assertRegExp('/[a-f0-9]+/', $commit->getHash());
$this->assertRegExp('/[a-f0-9]+/', $commit->getShortHash());
$this->assertRegExp('/[a-f0-9]+/', $commit->getTreeHash());
}
}
/**
* @depends testIsGettingCommits
*/
public function testIsGettingCommitsFromSpecificFile()
{
$repository = $this->client->getRepository($this->repoPath);
$commits = $repository->getCommits('test_file4.txt');
foreach ($commits as $commit) {
$this->assertInstanceOf('Git\Commit\Commit', $commit);
$this->assertTrue($commit->getMessage() === 'The truth unveiled');
$this->assertInstanceOf('Git\Commit\Author', $commit->getAuthor());
$this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker');
$this->assertEquals($commit->getAuthor()->getEmail(), 'luke@republic.com');
}
}
public function testIsGettingTree()
{
$repository = $this->client->getRepository($this->repoPath);
$files = $repository->getTree('master');
foreach ($files as $file) {
$this->assertInstanceOf('Git\Model\Blob', $file);
$this->assertRegExp('/test_file[0-9]*.txt/', $file->getName());
$this->assertEquals($file->getSize(), '55');
$this->assertEquals($file->getMode(), '100644');
$this->assertRegExp('/[a-f0-9]+/', $file->getHash());
}
}
public function testIsGettingTreeOutput()
{
$repository = $this->client->getRepository($this->repoPath);
$files = $repository->getTree('master')->output();
foreach ($files as $file) {
$this->assertEquals('blob', $file['type']);
$this->assertRegExp('/test_file[0-9]*.txt/', $file['name']);
$this->assertEquals($file['size'], '55');
$this->assertEquals($file['mode'], '100644');
$this->assertRegExp('/[a-f0-9]+/', $file['hash']);
}
}
public function testIsGettingTreesWithinTree()
{
$repository = $this->client->getRepository($this->repoPath);
// Creating folders
mkdir($this->repoPath . '/MyFolder');
mkdir($this->repoPath . '/MyTest');
mkdir($this->repoPath . '/MyFolder/Tests');
// Populating created folders
file_put_contents($this->repoPath . '/MyFolder/crazy.php', 'Lorem ipsum dolor sit amet');
file_put_contents($this->repoPath . '/MyFolder/skywalker.php', 'Lorem ipsum dolor sit amet');
file_put_contents($this->repoPath . '/MyTest/fortytwo.php', 'Lorem ipsum dolor sit amet');
file_put_contents($this->repoPath . '/MyFolder/Tests/web.php', 'Lorem ipsum dolor sit amet');
file_put_contents($this->repoPath . '/MyFolder/Tests/cli.php', 'Lorem ipsum dolor sit amet');
// Adding and commiting
$repository->addAll();
$repository->commit("Creating folders for testIsGettingTreesWithinTrees");
// Checking tree
$files = $repository->getTree('master')->output();
$this->assertEquals('folder', $files[0]['type']);
$this->assertEquals('MyFolder', $files[0]['name']);
$this->assertEquals('', $files[0]['size']);
$this->assertEquals('040000', $files[0]['mode']);
$this->assertEquals('4143e982237f3bdf56b5350f862c334054aad69e', $files[0]['hash']);
$this->assertEquals('folder', $files[1]['type']);
$this->assertEquals('MyTest', $files[1]['name']);
$this->assertEquals('', $files[1]['size']);
$this->assertEquals('040000', $files[1]['mode']);
$this->assertEquals('632240595eabd59e4217d196d6c12efb81f9c011', $files[1]['hash']);
$this->assertEquals('blob', $files[2]['type']);
$this->assertEquals('test_file.txt', $files[2]['name']);
$this->assertEquals('55', $files[2]['size']);
$this->assertEquals('100644', $files[2]['mode']);
$this->assertEquals('a773bfc0fda6f878e3d17d78c667d18297c8831f', $files[2]['hash']);
}
public function testIsGettingBlobsWithinTrees()
{
$repository = $this->client->getRepository($this->repoPath);
$files = $repository->getTree('master:MyFolder/')->output();
$this->assertEquals('folder', $files[0]['type']);
$this->assertEquals('Tests', $files[0]['name']);
$this->assertEquals('', $files[0]['size']);
$this->assertEquals('040000', $files[0]['mode']);
$this->assertEquals('8542f67d011ff2ea5ec49a729ba81a52935676d1', $files[0]['hash']);
$this->assertEquals('blob', $files[1]['type']);
$this->assertEquals('crazy.php', $files[1]['name']);
$this->assertEquals('26', $files[1]['size']);
$this->assertEquals('100644', $files[1]['mode']);
$this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[1]['hash']);
$this->assertEquals('blob', $files[2]['type']);
$this->assertEquals('skywalker.php', $files[2]['name']);
$this->assertEquals('26', $files[2]['size']);
$this->assertEquals('100644', $files[2]['mode']);
$this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[2]['hash']);
}
public function testIsGettingBlobOutput()
{
$repository = $this->client->getRepository($this->repoPath);
$blob = $repository->getBlob('master:MyFolder/crazy.php')->output();
$this->assertEquals('Lorem ipsum dolor sit amet', $blob);
$blob = $repository->getBlob('master:test_file4.txt')->output();
$this->assertEquals('Your mother is so ugly, glCullFace always returns TRUE.', $blob);
}
public function testIsGettingStatistics()
{
$repository = $this->client->getRepository($this->repoPath);
$stats = $repository->getStatistics('master');
$this->assertEquals('10', $stats['extensions']['.txt']);
$this->assertEquals('5', $stats['extensions']['.php']);
$this->assertEquals('680', $stats['size']);
$this->assertEquals('15', $stats['files']);
}
public function testIsGettingAuthorStatistics()
{
$repository = $this->client->getRepository($this->repoPath);
$stats = $repository->getAuthorStatistics();
$this->assertEquals('Luke Skywalker', $stats[0]['name']);
$this->assertEquals('luke@republic.com', $stats[0]['email']);
$this->assertEquals('2', $stats[0]['commits']);
$repository->setConfig('user.name', 'Princess Leia');
$repository->setConfig('user.email', 'sexyleia@republic.com');
file_put_contents($this->repoPath . '/MyFolder/crazy.php', 'Lorem ipsum dolor sit AMET');
$repository->addAll();
$repository->commit("Fixing AMET case");
$stats = $repository->getAuthorStatistics();
$this->assertEquals('Luke Skywalker', $stats[0]['name']);
$this->assertEquals('luke@republic.com', $stats[0]['email']);
$this->assertEquals('2', $stats[0]['commits']);
$this->assertEquals('Princess Leia', $stats[1]['name']);
$this->assertEquals('sexyleia@republic.com', $stats[1]['email']);
$this->assertEquals('1', $stats[1]['commits']);
}
public static function tearDownAfterClass()
{
recursiveDelete('/tmp/gitlist');
}
}
views/ 0000775 0000000 0000000 00000000000 15161610567 0012223 5 ustar 00root root 0000000 0000000 views/blame.twig 0000664 0000000 0000000 00000001656 15161610567 0014207 0 ustar 00root root 0000000 0000000 {% extends 'layout.twig' %}
{% block title %}GitList{% endblock %}
{% block body %}
{% include 'navigation.twig' %}
{% include 'menu.twig' %}
{% include 'footer.twig' %}
{% endblock %}
views/branch_menu.twig 0000664 0000000 0000000 00000001145 15161610567 0015401 0 ustar 00root root 0000000 0000000