updated-packages

This commit is contained in:
RafficMohammed
2023-01-08 00:13:22 +05:30
parent 3ff7df7487
commit da241bacb6
12659 changed files with 563377 additions and 510538 deletions

View File

@@ -0,0 +1,132 @@
# CONTRIBUTOR COVENANT CODE OF CONDUCT
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@gjcampbell.co.uk.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -0,0 +1,32 @@
# CONTRIBUTION GUIDELINES
Contributions are **welcome** and will be fully **credited**.
We accept contributions via pull requests on GitHub. Please review these guidelines before continuing.
## Guidelines
* Please follow the [PSR-12 Coding Style Guide](https://www.php-fig.org/psr/psr-12/), enforced by [StyleCI](https://styleci.io/).
* Ensure that the current tests pass, and if you've added something new, add the tests where relevant.
* Send a coherent commit history, making sure each commit in your pull request is meaningful.
* You may need to [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) to avoid merge conflicts.
* If you are changing or adding to the behaviour or public API, you may need to update the docs.
* Please remember that we follow [Semantic Versioning](https://semver.org/).
## Running Tests
First, install the dependencies using [Composer](https://getcomposer.org/):
```bash
$ composer install
```
Then run [PHPUnit](https://phpunit.de/):
```bash
$ vendor/bin/phpunit
```
* A script `test-git-version.sh` is available in repository to test gitlib against many git versions.
* The tests will be automatically run by [GitHub Actions](https://github.com/features/actions) against pull requests.
* We also have [StyleCI](https://styleci.io/) set up to automatically fix any code style issues.

View File

@@ -0,0 +1 @@
tidelift: "packagist/gitonomy/gitlib"

View File

@@ -0,0 +1,14 @@
# SECURITY POLICY
## Supported Versions
After each new major release, the previous release will be supported for no
less than 12 months, unless explictly stated otherwise. This may mean that
there are multiple supported versions at any given time.
## Reporting a Vulnerability
If you discover a security vulnerability within this package, please send an
email to security@tidelift.com. All security vulnerabilities will be promptly
addressed. Please do not disclose security-related issues publicly until a fix
has been announced.

View File

@@ -0,0 +1,96 @@
name: Tests
on:
push:
pull_request:
jobs:
tests:
name: PHP ${{ matrix.php }}; Symfony ${{ matrix.symfony }}
runs-on: ubuntu-20.04
strategy:
matrix:
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
symfony: ['3', '4', '5', '6']
exclude:
- php: '5.6'
symfony: '4'
- php: '5.6'
symfony: '5'
- php: '5.6'
symfony: '6'
- php: '7.0'
symfony: '4'
- php: '7.0'
symfony: '5'
- php: '7.0'
symfony: '6'
- php: '7.1'
symfony: '5'
- php: '7.1'
symfony: '6'
- php: '7.2'
symfony: '6'
- php: '7.3'
symfony: '6'
- php: '7.4'
symfony: '6'
- php: '8.1'
symfony: '3'
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: composer:v2
coverage: none
- name: Setup Problem Matchers
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Select Symfony 3
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer require "symfony/process:^3.4" --no-update --no-interaction
if: "matrix.symfony == '3'"
- name: Select Symfony 4
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer require "symfony/process:^4.4" --no-update --no-interaction
if: "matrix.symfony == '4'"
- name: Select Symfony 5
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer require "symfony/process:^5.3" --no-update --no-interaction
if: "matrix.symfony == '5'"
- name: Select Symfony 6
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer require "symfony/process:^6.0" --no-update --no-interaction
if: "matrix.symfony == '6'"
- name: Install PHP Dependencies
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer update --no-interaction --no-progress
- name: Execute PHPUnit
run: vendor/bin/phpunit

View File

@@ -1,3 +1,4 @@
/vendor
/.phpunit.result.cache
/composer.lock
/phpunit.xml
/vendor

View File

@@ -1,26 +0,0 @@
language: php
sudo: false
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- hhvm
matrix:
include:
- php: 5.3
dist: precise
before_install:
# turn off XDebug, if present
- phpenv config-rm xdebug.ini || return 0
install:
- composer install --no-interaction --no-progress
script: vendor/bin/phpunit

View File

@@ -1,12 +1,73 @@
Git lib for Gitonomy
====================
Gitlib for Gitonomy
===================
[![Build Status](https://secure.travis-ci.org/gitonomy/gitlib.png)](https://travis-ci.org/gitonomy/gitlib)
[![Build Status](https://img.shields.io/github/workflow/status/gitonomy/gitlib/Tests/1.3?label=Tests&style=flat-square)](https://github.com/gitonomy/gitlib/actions?query=workflow%3ATests+branch%3A1.3)
[![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=1.3)](https://github.styleci.io/repos/5709354?branch=1.3)
[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://opensource.org/licenses/MIT)
[![Downloads](https://img.shields.io/packagist/dt/gitonomy/gitlib?style=flat-square)](https://packagist.org/packages/gitonomy/gitlib)
This library provides methods to access Git repository from PHP.
This library provides methods to access Git repository from PHP 5.6+.
It makes shell calls, which makes it less performant than any solution.
Anyway, it's convenient and don't need to build anything to use it. That's how we love it.
*Documentation*: http://gitonomy.com/doc/gitlib/master/
Quick Start
-----------
You can install gitlib using [Composer](https://getcomposer.org/). Simply require the version you need:
```bash
$ composer require gitonomy/gitlib
```
or edit your `composer.json` file by hand:
```json
{
"require": {
"gitonomy/gitlib": "^1.3"
}
}
```
Example Usage
-------------
```php
<?php
use Gitonomy\Git\Repository;
$repository = new Repository('/path/to/repository');
foreach ($repository->getReferences()->getBranches() as $branch) {
echo '- '.$branch->getName().PHP_EOL;
}
$repository->run('fetch', ['--all']);
```
API Documentation
-----------------
+ [Admin](doc/admin.md)
+ [Blame](doc/blame.md)
+ [Blob](doc/blob.md)
+ [Branch](doc/branch.md)
+ [Commit](doc/commit.md)
+ [Diff](doc/diff.md)
+ [Hooks](doc/hooks.md)
+ [Log](doc/log.md)
+ [References](doc/references.md)
+ [Repository](doc/repository.md)
+ [Revision](doc/revision.md)
+ [Tree](doc/tree.md)
+ [Working Copy](doc/workingcopy.md)
For Enterprise
--------------
Available as part of the Tidelift Subscription
The maintainers of `gitonomy/gitlib` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-gitonomy-gitlib?utm_source=packagist-gitonomy-gitlib&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)

View File

@@ -4,17 +4,26 @@
"license": "MIT",
"authors": [
{
"name": "Alexandre Salomé",
"email": "alexandre.salome@gmail.com",
"homepage": "http://alexandre-salome.fr"
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Julien DIDIER",
"name": "Julien Didier",
"email": "genzo.wm@gmail.com",
"homepage": "http://www.jdidier.net"
"homepage": "https://github.com/juliendidier"
},
{
"name": "Grégoire Pineau",
"email": "lyrixx@lyrixx.info",
"homepage": "https://github.com/lyrixx"
},
{
"name": "Alexandre Salomé",
"email": "alexandre.salome@gmail.com",
"homepage": "https://github.com/alexandresalome"
}
],
"homepage": "http://gitonomy.com",
"autoload": {
"psr-4": {
"Gitonomy\\Git\\": "src/Gitonomy/Git/"
@@ -26,19 +35,24 @@
}
},
"require": {
"php": "^5.3 || ^7.0",
"symfony/process": "^2.3|^3.0|^4.0"
"php": "^5.6 || ^7.0 || ^8.0",
"ext-pcre": "*",
"symfony/polyfill-mbstring": "^1.7",
"symfony/process": "^3.4 || ^4.4 || ^5.0 || ^6.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.7",
"ext-fileinfo": "*",
"phpspec/prophecy": "^1.10.2",
"phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.20 || ^9.5.9",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Add some log"
"ext-fileinfo": "Required to determine the mimetype of a blob",
"psr/log": "Required to use loggers for reporting of execution"
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
"config": {
"preferred-install": "dist"
},
"minimum-stability": "dev",
"prefer-stable": true
}

77
vendor/gitonomy/gitlib/doc/admin.md vendored Normal file
View File

@@ -0,0 +1,77 @@
Create and access git repositories
==================================
gitlib provides methods to initialize new repositories.
Create a repository
-------------------
To initialize a new repository, use method `Admin::init`.
```php
// Initialize a bare repository
$repository = Gitonomy\Git\Admin::init('/path/to/repository');
// Initialize a non-bare repository
$repository = Gitonomy\Git\Admin::init('/path/to/repository', false);
```
Default behavior is to create a bare repository. If you want to
initialize a repository with a working copy,pass `false` as third
argument of Repository constructor.
Cloning repositories
--------------------
You can clone a repository from an URL by doing:
```php
// Clone to a bare repository
$repository = Gitonomy\Git\Admin::cloneTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git');
// Clone to a non-bare repository
$repository = Gitonomy\Git\Admin::cloneTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', false);
```
Default behavior is to clone in a bare repository.
You can also clone a repository and point it to a specific branch. In a
non-bare repository, this branch will be checked out:
```php
// Clone to a bare repository
$repository = Gitonomy\Git\Admin::cloneBranchTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', 'a-branch');
// Clone to a non-bare repository
$repository = Gitonomy\Git\Admin::cloneBranchTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', 'a-branch', false);
```
Clone a Repository object
-------------------------
If you already have a Repository instance and want to clone it, you can
use this shortcut:
```php
$new = $repository->cloneTo('/tmp/clone');
```
Mirror a repository
-------------------
If you want to mirror fully a repository and all references, use the
`mirrorTo` method. This method takes only two arguments, where to mirror
and what to mirror:
```php
// Mirror to a bare repository
$mirror = Gitonomy\Git\Admin::mirrorTo('/tmp/mirror', 'https://github.com/gitonomy/gitlib.git');
// Mirror to a non-bare repository
$mirror = Gitonomy\Git\Admin::mirrorTo('/tmp/mirror', 'https://github.com/gitonomy/gitlib.git', false);
```
### References
- <http://linux.die.net/man/1/git-init>
- <http://linux.die.net/man/1/git-clone>

View File

@@ -1,76 +0,0 @@
Create and access git repositories
==================================
gitlib provides methods to initialize new repositories.
Create a repository
-------------------
To initialize a new repository, use method ``Admin::init``.
.. code-block:: php
// Initialize a bare repository
$repository = Gitonomy\Git\Admin::init('/path/to/repository');
// Initialize a non-bare repository
$repository = Gitonomy\Git\Admin::init('/path/to/repository', false);
Default behavior is to create a bare repository. If you want to initialize a
repository with a working copy,pass ``false`` as third argument of Repository
constructor.
Cloning repositories
--------------------
You can clone a repository from an URL by doing:
.. code-block:: php
// Clone to a bare repository
$repository = Gitonomy\Git\Admin::cloneTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git');
// Clone to a non-bare repository
$repository = Gitonomy\Git\Admin::cloneTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', false);
Default behavior is to clone in a bare repository.
You can also clone a repository and point it to a specific branch. In a non-bare repository, this branch will be checked out:
.. code-block:: php
// Clone to a bare repository
$repository = Gitonomy\Git\Admin::cloneBranchTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', 'a-branch');
// Clone to a non-bare repository
$repository = Gitonomy\Git\Admin::cloneBranchTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', 'a-branch' false);
Clone a Repository object
-------------------------
If you already have a Repository instance and want to clone it, you can use this shortcut:
.. code-block:: php
$new = $repository->cloneTo('/tmp/clone');
Mirror a repository
-------------------
If you want to mirror fully a repository and all references, use the ``mirrorTo`` method. This method
takes only two arguments, where to mirror and what to mirror:
.. code-block:: php
// Mirror to a bare repository
$mirror = Gitonomy\Git\Admin::mirrorTo('/tmp/mirror', 'https://github.com/gitonomy/gitlib.git');
// Mirror to a non-bare repository
$mirror = Gitonomy\Git\Admin::mirrorTo('/tmp/mirror', 'https://github.com/gitonomy/gitlib.git', false);
References
::::::::::
* http://linux.die.net/man/1/git-init
* http://linux.die.net/man/1/git-clone

View File

@@ -1,54 +0,0 @@
Blaming files
=============
Line-per-line iteration
-----------------------
To iterate on lines of a blame:
.. code-block:: php
$blame = $repository->getBlame('master', 'README.md');
foreach ($blame->getLines() as $lineNumber => $line) {
$commit = $line->getCommit();
echo $lineNumber.': '.$line->getContent()." - ".$commit->getAuthorName()."\n";
}
The *getLines* method returns an array indexed starting from 1.
As you can see, you can access the commit object related to the line you are iterating on.
If you want to access directly a line:
.. code-block:: php
$line = $blame->getLine(32);
The Line object
---------------
LineObject represents an item of the blame file. It is composed of those informations:
.. code-block:: php
$line->getCommit(); // returns a Commit
$line->getContent(); // returns text
// you can access author from commmit:
$author = $line->getCommit()->getAuthorName();
Group reading by commit
-----------------------
If you plan to display it, you'll probably need a version where lines from same commit are grouped.
To do so, use the *getGroupedLines* method that will return an array like this:
.. code-block:: php
$blame = array(
array(Commit, array(1 => Line, 2 => Line, 3 => Line)),
array(Commit, array(4 => Line)),
array(Commit, array(5 => Line, 6 => Line))
)

View File

@@ -1,16 +0,0 @@
Branch
======
To access a *Branch*, starting from a repository object:
.. code-block:: php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$branch = $repository->getReferences()->getBranch('master');
You can check is the branch is a local or remote one:
.. code-block:: php
$branch->isLocal();
$branch->isRemote();

View File

@@ -1,168 +0,0 @@
Commit
======
To access a *Commit*, starting from a repository object:
.. code-block:: php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$commit = $repository->getCommit('a7c8d2b4');
Browsing parents
----------------
A *Commit* can have a natural number of parents:
* **no parent**: it's an initial commit, the root of a tree
* **one parent**: it means it's not a merge, just a regular commit
* **many parents**: it's a merge-commit
You have 2 methods available for accessing parents:
.. code-block:: php
// Access parent hashes
$hashes = $commit->getParentHashes();
// Access parent commit objects
$commits = $commit->getParents();
For example, if you want to display all parents, starting from a commit:
.. code-block:: php
function displayLog(Gitonomy\Git\Commit $commit) {
echo '- '.$commit->getShortMessage()."\n";
foreach ($commit->getParents() as $parent) {
displayLog($parent);
}
}
Notice that this function will first display all commits from first merged
branch and then display all commits from next branch, and so on.
Accessing tree
--------------
The tree object contains the reference to the files associated to a given
commit. Every commit has one and only one tree, referencing all files and
folders of a given state for a project. For more informations about the tree,
see the chapter dedicated to it.
To access a tree starting from a commit:
.. code-block:: php
// Returns the tree hash
$tree = $commit->getTreeHash();
// Returns the tree object
$tree = $commit->getTree();
Author & Committer informations
-------------------------------
Each commit has two authoring informations: an author and a committer. The
author is the creator of the modification, authoring a modification in the
repository. The committer is responsible of introducing this modification to
the repository.
You can access informations from author and committer using those methods:
.. code-block:: php
// Author
$commit->getAuthorName();
$commit->getAuthorEmail();
$commit->getAuthorDate(); // returns a DateTime object
// Committer
$commit->getCommitterName();
$commit->getCommitterEmail();
$commit->getCommitterDate(); // returns a DateTime object
Commit message and short message
--------------------------------
Each commit also has a message, associated to the modification. This message
can be multilined.
To access the message, you can use the *getMessage* method:
.. code-block:: php
$commit->getMessage();
For your convenience, this library provides a shortcut method to keep only the
first line or first 50 characters if the first line is too long:
.. code-block:: php
$commit->getShortMessage();
You can customize it like this:
.. code-block:: php
$commit->getShortMessage(45, true, '.');
* The first parameter is the max length of the message.
* The second parameter determine if the last word should be cut or preserved
* The third parameter is the separator
There are also two other methods for your convenience:
.. code-block:: php
// The first line
$commit->getSubjectMessage();
// The body (rest of the message)
$commit->getBodyMessage();
Diff of a commit
----------------
You can check the modifications introduced by a commit using the *getDiff*
method. When you request a diff for a commit, depending of the number of
parents, the strategy will be different:
* If you have *no parent*, the diff will be the content of the tree
* If you only have *one parent*, the diff will be between the commit and his
parent
* If you have *multiple parents*, the diff will be the difference between the
commit and the first common ancestor of all parents
For more informations about the diff API, read the related chapter.
To access the *Diff* object of a commit, use the method *getDiff*:
.. code-block:: php
$diff = $commit->getDiff();
Last modification of a file
---------------------------
To know the last modification of a file, you can use the *getLastModification*
method on a commit.
Here is a very straightforward example:
.. code-block:: php
$last = $commit->getLastModification('README');
echo "Last README modification:\n";
echo" Author: ".$last->getAuthorName()."\n";
echo" Date: ".$last->getAuthorDate()->format('d/m/Y')."\n";
echo" Message: ".$last->getMessage();
Find every branches containing a commit
---------------------------------------
.. code-block:: php
$branches = $commit->getIncludingBranches($includeLocalBranches, $includeRemoteBranches);
$localBranches = $commit->getIncludingBranches(true, false);
$remoteBranches = $commit->getIncludingBranches(false, true);

View File

@@ -1,102 +0,0 @@
Computing diff
==============
Even if git is a diff-less storage engine, it's possible to compute them.
To compute a diff in git, you need to specify a *revision*. This revision can
be a commit (*2bc7a8*) or a range (*2bc7a8..ff4c21b*).
For more informations about git revisions: *man gitrevisions*.
When you have decided the revision you want and have your *Repository* object,
you can call the *getDiff* method on the repository:
.. code-block:: php
$diff = $repository->getDiff('master@{2 days ago}..master');
You can also access it from a *Log* object:
.. code-block:: php
$log = $repository->getLog('master@{2 days ago}..master');
$diff = $log->getDiff();
Iterating a diff
----------------
When you have a *Diff* object, you can iterate over files using method
*getFiles()*. This method returns a list of *File* objects, who represents the
modifications for a single file.
.. code-block:: php
$files = $diff->getFiles();
echo sprintf("%s files modified", count($files));
foreach ($files as $fileDiff) {
echo sprintf("Old name: (%s) %s\n", $fileDiff->getOldMode(), $fileDiff->getOldName());
echo sprintf("New name: (%s) %s\n", $fileDiff->getNewMode(), $fileDiff->getNewName());
}
The File object
---------------
Here is an exhaustive list of the *File* class methods:
.. code-block:: php
$file->getOldName();
$file->getNewName();
$file->getOldDiff();
$file->getNewDiff();
$file->isCreation();
$file->isDeletion();
$file->isModification();
$file->isRename();
$file->isChangeMode();
$file->getAdditions(); // Number of added lines
$file->getDeletions(); // Number of deleted lines
$file->isBinary(); // Binary files have no "lines"
$file->getChanges(); // See next chapter
The FileChange object
---------------------
.. note::
This part of API is not very clean, very consistent. If you have any idea
or suggestion on how to enhance this, your comment would be appreciated.
A *File* object is composed of many changes. For each of those changes,
a *FileChange* object is associated.
To access changes from a file, use the *getChanges* method:
.. code-block:: php
$changes = $file->getChanges();
foreach ($changes as $change) {
foreach ($lines as $data) {
list ($type, $line) = $data;
if ($type === FileChange::LINE_CONTEXT) {
echo ' '.$line."\n";
} elseif ($type === FileChange::LINE_ADD) {
echo '+'.$line."\n";
} else {
echo '-'.$line."\n";
}
}
}
To get line numbers, use the range methods:
.. code-block:: php
echo sprintf("Previously from line %s to %s\n", $change->getOldRangeStart(), $change->getOldRangeEnd());
echo sprintf("Now from line %s to %s\n", $change->getNewRangeStart(), $change->getNewRangeEnd());

View File

@@ -1,76 +0,0 @@
Hooks
=====
It's possible to define custom hooks on any repository with git. Those hooks
are located in the *.git/hooks* folder.
Those files need to be executable. For convenience, gitlib will set them to
*777*.
With *gitlib*, you can manage hooks over a repository using the *Hooks* object.
To access it from a repository, use the *getHooks* method on a *Repository*
object:
.. code-block:: php
$hooks = $repository->getHooks();
Reading hooks
-------------
To read the content of a hook, use the *get* method like this:
.. code-block:: php
$content = $hooks->get('pre-receive'); // returns a string
If the hook does not exist, an exception will be thrown (*InvalidArgumentException*).
You can test if a hook is present using the method *has*:
.. code-block:: php
$hooks->has('pre-receive'); // a boolean indicating presence
Inserting hooks
---------------
You can modify a hook in two different ways: creating a new file or using a symlink.
To create the hook using a symlink:
.. code-block:: php
$hooks->setSymlink('pre-receive', '/path/to/file-to-link');
If the hook already exist, a *LogicException* will be thrown. If an error occured
during symlink creation, a *RuntimeException* will be thrown.
If you want to directly create a new file in hooks directory, use the
method *set*. This method will create a new file, put content in it and make it
executable:
.. code-block:: php
$content = <<<HOOK
#!/bin/bash
echo "Push is disabled"
exit 1
HOOK;
// this hook will reject every push
$hooks->set('pre-receive', $content);
If the hook already exists, a *LogicException* will be thrown.
Removing hooks
--------------
To remove a hook from a repository, use the function *remove*:
.. code-block:: php
$hooks->remove('pre-receive');

View File

@@ -1,54 +0,0 @@
Getting log history
===================
Crawling manually commits and parents to browse history is surely a good
solution. But when it comes to ordering them or aggregate them from multiple
branches, we tend to use ``git log``.
To get a *Log* object from a repository:
.. code-block:: php
$log = $repository->getLog();
You can pass four arguments to *getLog* method:
.. code-block:: php
// Global log for repository
$log = $repository->getLog();
// Log for master branch
$log = $repository->getLog('master');
// Returns last 10 commits on README file
$log = $repository->getLog('master', 'README', 0, 10);
// Returns last 10 commits on README or UPGRADE files
$log = $repository->getLog('master', array('README', 'UPGRADE'), 0, 10);
Counting
--------
If you want to count overall commits, without offset or limit, use the *countCommits* method:
.. code-block:: php
echo sprintf("This log contains %s commits\n", $log->countCommits());
// Countable interface
echo sprintf("This log contains %s commits\n", count($log));
Offset and limit
----------------
Use those methods:
.. code-block:: php
$log->setOffset(32);
$log->setLimit(40);
// or read it:
$log->getOffset();
$log->getLimit();

View File

@@ -1,91 +0,0 @@
Tags and branches
=================
Accessing tags and branches
---------------------------
With *gitlib*, you can access them via the *ReferenceBag* object. To get this
object from a *Repository*, use the *getReferences* method:
.. code-block:: php
$references = $repository->getReferences();
First, you can test existence of tags and branches like this:
.. code-block:: php
if ($references->hasBranch('master') && $references->hasTag('0.1')) {
echo "Good start!";
}
If you want to access all branches or all tags:
.. code-block:: php
$branches = $references->getBranches();
$localBranches = $references->getLocalBranches();
$remoteBranches = $references->getRemoteBranches();
$tags = $references->getTags();
$all = $references->getAll();
To get a given branch or tag, call *getBranch* or *getTag* on the
*ReferenceBag*. Those methods return *Branch* and *Tag* objects:
.. code-block:: php
$master = $references->getBranch('master');
$feat123 = $references->getLocalBranch('feat123');
$feat456 = $references->getRemoteBranch('origin/feat456');
$v0_1 = $references->getTag('0.1');
If the reference cannot be resolved, a *ReferenceNotFoundException* will be
thrown.
On each of those objects, you can access those informations:
.. code-block:: php
// Get the associated commit
$commit = $master->getCommit();
// Get the commit hash
$hash = $master->getCommitHash();
// Get the last modification
$lastModification = $master->getLastModification();
Create and delete reference
---------------------------
You can create new tags and branches on repository, using helper methods
on ReferenceBag object:
.. code-block:: php
// create a branch
$references = $repository->getReferences();
$branch = $references->createBranch('foobar', 'a8b7e4...'); // commit to reference
// create a tag
$references = $repository->getReferences();
$tag = $references->createTag('0.3', 'a8b7e4...'); // commit to reference
// delete a branch or a tag
$branch->delete();
Resolution from a commit
------------------------
To resolve a branch or a commit from a commit, you can use the *resolveTags*
and *resolveBranches* methods on it:
.. code-block:: php
$branches = $references->resolveBranches($commit);
$tags = $references->resolveTags($commit);
// Resolve branches and tags
$all = $references->resolve($commit);
You can pass a *Commit* object or a hash to the method, gitlib will handle it.

View File

@@ -1,135 +0,0 @@
Repository methods
==================
Creating a *Repository* object is possible, providing a *path* argument to the
constructor:
.. code-block:: php
$repository = new Repository('/path/to/repo');
Repository options
------------------
The constructor of Repository takes an additional parameter: ``$options``.
This parameter can be used used to tune behavior of library.
Available options are:
* **debug** (default: true): Enables exception when edge cases are met
* **environment_variables**: (default: none) An array of environment variables to be set in sub-process
* **logger**: (default: none) Logger to use for reporting of execution (a ``Psr\Log\LoggerInterface``)
* **command**: (default: ``git``) Specify command to execute to run git
* **working_dir**: If you are using multiple working directories, this option is for you
An example:
.. code-block:: php
$repository = new Repository('/path/to/repo', array(
'debug' => true,
'logger' => new Monolog\Logger()
));
Test if a repository is bare
----------------------------
On a *Repository* object, you can call method *isBare* to test if your repository is bare or not:
.. code-block:: php
$repository->isBare();
Compute size of a repository
----------------------------
To know how much size a repository is using on your drive, you can use ``getSize`` method on a *Repository* object.
.. warning:: This command was only tested with linux.
The returned size is in kilobytes:
.. code-block:: php
$size = $repository->getSize();
echo "Your repository size is ".$size."KB";
Access HEAD
-----------
``HEAD`` represents in git the version you are working on (in working tree).
Your ``HEAD`` can be attached (using a reference) or detached (using a commit).
.. code-block:: php
$head = $repository->getHead(); // Commit or Reference
$head = $repository->getHeadCommit(); // Commit
if ($repository->isHeadDetached()) {
echo "Sorry man\n";
}
Options for repository
----------------------
Logger
......
If you are developing, you may appreciate to have a logger inside repository, telling you every executed command.
You call method ``setLogger`` as an option on repository creation:
.. code-block:: php
$repository->setLogger(new Monolog\Logger('repository'));
$repository->run('fetch', array('--all'));
You can also specify as an option on repository creation:
$logger = new Monolog\Logger('repository');
$repository = new Repository('/path/foo', array('logger' => $logger));
$repository->run('fetch', array('--all'));
This will output:
.. code-block:: text
info run command: fetch "--all"
debug last command (fetch) duration: 23.24ms
debug last command (fetch) return code: 0
debug last command (fetch) output: Fetching origin
Disable debug-mode
..................
Gitlib throws an exception when something seems wrong. If a ``git` command returns a non-zero result, it will stop execution and throw an ``RuntimeException``.
If you want to prevent this, set ``debug`` option to ``false``. This will make Repository log errors and return empty data instead of throwing exceptions.
.. code-block:: php
$repository = new Repository('/tmp/foo', array('debug' => false, 'logger' => $logger));
.. note:: if you plan to disable debug, you should rely on logger to keep a trace of edge failing cases.
Specify git command to use
..........................
You can pass option ``command`` to specify which command to use to run git calls. If you have a git binary
located somewhere else, use this option to specify to gitlib path to your git binary:
.. code-block:: php
$repository = new Gitonomy\Git\Repository('/tmp/foo', array('command' => '/home/alice/bin/git'));
Environment variables
.....................
Now you want to set environment variables to use to run ``git`` commands. It might be useful.
.. code-block:: php
$repository = new Gitonomy\Git\Repository('/tmp/foo', array('environment_variables' => array('GIT_')))

View File

@@ -1,28 +0,0 @@
Revision
========
To get a revision from a *Repository* object:
.. code-block:: php
$revision = $repository->getRevision('master@{2 days ago}');
Getting the log
---------------
You can access a *Log* object starting from a revision using the *getLog*
method. This method takes two parameters: *offset* and *limit*:
.. code-block:: php
// Returns 100 lasts commits
$log = $revision->getLog(null, 100);
Resolve a revision
------------------
To resolve a revision to a commit:
.. code-block:: php
$commit = $revision->getCommit();

View File

@@ -1,54 +0,0 @@
Tree and files
==============
To organize folders, git uses trees. In gitlib, those trees are represented
via *Tree* object.
To get the root tree associated to a commit, use the *getTree* method on the
commit object:
.. code-block:: php
$tree = $commit->getTree();
This tree is the entry point of all of your files.
The main method for a tree is the *getEntries* method. This method will
return an array, indexed by name. Each of those elements will be the entry mode
and the entry object.
Let's understand how it works with a concrete example:
.. code-block:: php
function displayTree(Tree $tree, $indent = 0)
{
$indent = str_repeat(' ', $indent);
foreach ($tree->getEntries() as $name => $data) {
list($mode, $entry) = $data;
if ($entry instanceof Tree) {
echo $indent.$name."/\n";
displayTree($tree, $indent + 1);
} else {
echo $indent.$name."\n";
}
}
}
displayTree($commit->getTree());
This method will recursively display all entries of a tree.
Resolve a path
--------------
To access directly a sub-file, the easier is probably to use the *resolvePath*
method.
An example:
.. code-block:: php
$source = $tree->resolvePath('src/Gitonomy/Git');
$source instanceof Tree;

View File

@@ -1,45 +0,0 @@
Working copy
============
Working copy is the folder associated to a git repository. In *gitlib*, you
can access this object using the *getWorkingCopy* on a *Repository* object:
.. code-block:: php
$repo = new Repository('/path/to/working-dir');
$wc = $repo->getWorkingCopy();
Checkout a revision
-------------------
You can checkout any revision using *checkout* method. You can also pass a
second argument, which will be passed as argument with ``-b``:
.. code-block:: php
// git checkout master
$wc->checkout('master');
// git checkout origin/master -b master
$wc->checkout('origin/master', 'master');
You can also pass a *Reference* or a *Commit*.
Staged modifications
--------------------
You can get a diff of modifications pending in staging area. To get the ``Diff`` object,
call method ``getDiffStaged()``:
.. code-block:: php
$diff = $wc->getDiffStaged();
Pending modifications
---------------------
You can get pending modifications on tracked files by calling method ``getDiffPending()``:
.. code-block:: php
$diff = $wc->getDiffPending();

58
vendor/gitonomy/gitlib/doc/blame.md vendored Normal file
View File

@@ -0,0 +1,58 @@
Blaming files
=============
Line-per-line iteration
-----------------------
To iterate on lines of a blame:
```php
$blame = $repository->getBlame('master', 'README.md');
foreach ($blame->getLines() as $lineNumber => $line) {
$commit = $line->getCommit();
echo $lineNumber.': '.$line->getContent().' - '.$commit->getAuthorName().PHP_EOL;
}
```
The *getLines* method returns an array indexed starting from 1.
As you can see, you can access the commit object related to the line you
are iterating on.
If you want to access directly a line:
```php
$line = $blame->getLine(32);
```
The Line object
---------------
LineObject represents an item of the blame file. It is composed of those
informations:
```php
$line->getCommit(); // returns a Commit
$line->getContent(); // returns text
// you can access author from commmit:
$author = $line->getCommit()->getAuthorName();
```
Group reading by commit
-----------------------
If you plan to display it, you'll probably need a version where lines
from same commit are grouped.
To do so, use the *getGroupedLines* method that will return an array
like this:
```php
$blame = array(
array(Commit, array(1 => Line, 2 => Line, 3 => Line)),
array(Commit, array(4 => Line)),
array(Commit, array(5 => Line, 6 => Line))
)
```

View File

@@ -2,43 +2,43 @@ Blob
====
In git, a blob represents a file content. You can't access the file name
directly from the *Blob* object; the filename information is stored within
the tree, not in the blob.
directly from the *Blob* object; the filename information is stored
within the tree, not in the blob.
It means that for git, two files with different names but same content will
have the same hash.
It means that for git, two files with different names but same content
will have the same hash.
To access a repository *Blob*, you need the hash identifier:
.. code-block:: php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$blob = $repository->getBlob('a7c8d2b4');
```php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$blob = $repository->getBlob('a7c8d2b4');
```
Get content
-----------
To get content from a *Blob* object:
.. code-block:: php
echo $blob->getContent();
```php
echo $blob->getContent();
```
File informations
-----------------
To get mimetype of a *Blob* object using finfo extension:
.. code-block:: php
echo $blob->getMimetype();
```php
echo $blob->getMimetype();
```
You can also test if *Blob* is a text of a binary file:
.. code-block:: php
if ($blob->isText()) {
echo $blob->getContent(), "\n";
} elseif ($blob->isBinary()) {
echo "File is binary\n";
}
```php
if ($blob->isText()) {
echo $blob->getContent(), PHP_EOL;
} elseif ($blob->isBinary()) {
echo 'File is binary', PHP_EOL;
}
```

16
vendor/gitonomy/gitlib/doc/branch.md vendored Normal file
View File

@@ -0,0 +1,16 @@
Branch
======
To access a *Branch*, starting from a repository object:
```php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$branch = $repository->getReferences()->getBranch('master');
```
You can check is the branch is a local or remote one:
```php
$branch->isLocal();
$branch->isRemote();
```

171
vendor/gitonomy/gitlib/doc/commit.md vendored Normal file
View File

@@ -0,0 +1,171 @@
Commit
======
To access a *Commit*, starting from a repository object:
```php
$repository = new Gitonomy\Git\Repository('/path/to/repository');
$commit = $repository->getCommit('a7c8d2b4');
```
Browsing parents
----------------
A *Commit* can have a natural number of parents:
- **no parent**: it's an initial commit, the root of a tree
- **one parent**: it means it's not a merge, just a regular commit
- **many parents**: it's a merge-commit
You have 2 methods available for accessing parents:
```php
// Access parent hashes
$hashes = $commit->getParentHashes();
// Access parent commit objects
$commits = $commit->getParents();
```
For example, if you want to display all parents, starting from a commit:
```php
function displayLog(Gitonomy\Git\Commit $commit) {
echo '- '.$commit->getShortMessage().PHP_EOL;
foreach ($commit->getParents() as $parent) {
displayLog($parent);
}
}
```
Notice that this function will first display all commits from first
merged branch and then display all commits from next branch, and so on.
Accessing tree
--------------
The tree object contains the reference to the files associated to a
given commit. Every commit has one and only one tree, referencing all
files and folders of a given state for a project. For more informations
about the tree, see the chapter dedicated to it.
To access a tree starting from a commit:
```php
// Returns the tree hash
$tree = $commit->getTreeHash();
// Returns the tree object
$tree = $commit->getTree();
```
Author & Committer informations
-------------------------------
Each commit has two authoring informations: an author and a committer.
The author is the creator of the modification, authoring a modification
in the repository. The committer is responsible of introducing this
modification to the repository.
You can access informations from author and committer using those
methods:
```php
// Author
$commit->getAuthorName();
$commit->getAuthorEmail();
$commit->getAuthorDate(); // returns a DateTime object
// Committer
$commit->getCommitterName();
$commit->getCommitterEmail();
$commit->getCommitterDate(); // returns a DateTime object
```
Commit message and short message
--------------------------------
Each commit also has a message, associated to the modification. This
message can be multilined.
To access the message, you can use the *getMessage* method:
```php
$commit->getMessage();
```
For your convenience, this library provides a shortcut method to keep
only the first line or first 50 characters if the first line is too
long:
```php
$commit->getShortMessage();
```
You can customize it like this:
```php
$commit->getShortMessage(45, true, '.');
```
- The first parameter is the max length of the message.
- The second parameter determine if the last word should be cut or
preserved
- The third parameter is the separator
There are also two other methods for your convenience:
```php
// The first line
$commit->getSubjectMessage();
// The body (rest of the message)
$commit->getBodyMessage();
```
Diff of a commit
----------------
You can check the modifications introduced by a commit using the
*getDiff* method. When you request a diff for a commit, depending of the
number of parents, the strategy will be different:
- If you have *no parent*, the diff will be the content of the tree
- If you only have *one parent*, the diff will be between the commit
and his parent
- If you have *multiple parents*, the diff will be the difference
between the commit and the first common ancestor of all parents
For more informations about the diff API, read the related chapter.
To access the *Diff* object of a commit, use the method *getDiff*:
```php
$diff = $commit->getDiff();
```
Last modification of a file
---------------------------
To know the last modification of a file, you can use the
*getLastModification* method on a commit.
Here is a very straightforward example:
```php
$last = $commit->getLastModification('README');
echo 'Last README modification'.PHP_EOL;
echo ' Author: '.$last->getAuthorName().PHP_EOL;
echo ' Date: '.$last->getAuthorDate()->format('d/m/Y').PHP_EOL;
echo ' Message: '.$last->getMessage();
```
Find every branches containing a commit
---------------------------------------
```php
$branches = $commit->getIncludingBranches($includeLocalBranches, $includeRemoteBranches);
$localBranches = $commit->getIncludingBranches(true, false);
$remoteBranches = $commit->getIncludingBranches(false, true);
```

View File

@@ -1,22 +0,0 @@
Debug-mode
==========
gitlib offers a debug mode, to make you see edge-cases of your usage. This is called
debug-mode.
Debug-mode is enabled by default. If you disable it, gitlib will behave differently:
* when an error is met during execution, gitlib will try to minimize it, to not block
execution flow. Errors will still be reporter in logger.
* logs will be more verbose. They will contain every output, every return code, every
possible information to ease debugging.
If you want to disable exceptions and try to minimize as much as possible errors, pass
``false`` when construction a repository:
.. code-block:: php
$repository = new Gitonomy\Git\Repository($path'/tmp/repo', $debug = false)
``$debug`` argument should be available in every method you can use to create a
repository.

View File

@@ -1,24 +0,0 @@
Developing gitlib
=================
If you plan to contribute to gitlib, here are few things you should know:
Documentation generation
::::::::::::::::::::::::
Documentation is generated using Sphinx (restructured text). Configuration file
is located in https://github.com/gitonomy/website/blob/master/bin/conf.py
You will need to fetch vendor modules for PHP blocks especially. If you really
want to generate it, install the website project locally and hack into it.
Test against different git versions
:::::::::::::::::::::::::::::::::::
A script ``test-git-version.sh`` is available in repository to test gitlib against
many git versions.
This script is not usable on Travis-CI, they would hate me for this. It creates
a local cache to avoid fetching from Github and compiling if already compiled.
Use it at your own risk, it's still under experiment.

104
vendor/gitonomy/gitlib/doc/diff.md vendored Normal file
View File

@@ -0,0 +1,104 @@
Computing diff
==============
Even if git is a diff-less storage engine, it's possible to compute
them.
To compute a diff in git, you need to specify a *revision*. This
revision can be a commit (*2bc7a8*) or a range (*2bc7a8..ff4c21b*).
For more informations about git revisions: *man gitrevisions*.
When you have decided the revision you want and have your *Repository*
object, you can call the *getDiff* method on the repository:
```php
$diff = $repository->getDiff('master@{2 days ago}..master');
```
You can also access it from a *Log* object:
```php
$log = $repository->getLog('master@{2 days ago}..master');
$diff = $log->getDiff();
```
Iterating a diff
----------------
When you have a *Diff* object, you can iterate over files using method
*getFiles()*. This method returns a list of *File* objects, who
represents the modifications for a single file.
```php
$files = $diff->getFiles();
echo sprintf('%s files modified%s', count($files), PHP_EOL);
foreach ($files as $fileDiff) {
echo sprintf('Old name: (%s) %s%s', $fileDiff->getOldMode(), $fileDiff->getOldName(), PHP_EOL);
echo sprintf('New name: (%s) %s%s', $fileDiff->getNewMode(), $fileDiff->getNewName(), PHP_EOL);
}
```
The File object
---------------
Here is an exhaustive list of the *File* class methods:
```php
$file->getOldName();
$file->getNewName();
$file->getOldDiff();
$file->getNewDiff();
$file->isCreation();
$file->isDeletion();
$file->isModification();
$file->isRename();
$file->isChangeMode();
$file->getAdditions(); // Number of added lines
$file->getDeletions(); // Number of deleted lines
$file->isBinary(); // Binary files have no "lines"
$file->getChanges(); // See next chapter
```
The FileChange object
---------------------
> **note**
>
> This part of API is not very clean, very consistent. If you have any
> idea or suggestion on how to enhance this, your comment would be
> appreciated.
A *File* object is composed of many changes. For each of those changes,
a *FileChange* object is associated.
To access changes from a file, use the *getChanges* method:
```php
$changes = $file->getChanges();
foreach ($changes as $change) {
foreach ($lines as $data) {
list ($type, $line) = $data;
if ($type === FileChange::LINE_CONTEXT) {
echo ' '.$line.PHP_EOL;
} elseif ($type === FileChange::LINE_ADD) {
echo '+'.$line.PHP_EOL;
} else {
echo '-'.$line.PHP_EOL;
}
}
}
```
To get line numbers, use the range methods:
```php
echo sprintf('Previously from line %s to %s%s', $change->getOldRangeStart(), $change->getOldRangeEnd(), PHP_EOL);
echo sprintf('Now from line %s to %s%s', $change->getNewRangeStart(), $change->getNewRangeEnd(), PHP_EOL);
```

80
vendor/gitonomy/gitlib/doc/hooks.md vendored Normal file
View File

@@ -0,0 +1,80 @@
Hooks
=====
It's possible to define custom hooks on any repository with git. Those
hooks are located in the *.git/hooks* folder.
Those files need to be executable. For convenience, gitlib will set them
to *777*.
With *gitlib*, you can manage hooks over a repository using the *Hooks*
object.
To access it from a repository, use the *getHooks* method on a
*Repository* object:
```php
$hooks = $repository->getHooks();
```
Reading hooks
-------------
To read the content of a hook, use the *get* method like this:
```php
$content = $hooks->get('pre-receive'); // returns a string
```
If the hook does not exist, an exception will be thrown
(*InvalidArgumentException*).
You can test if a hook is present using the method *has*:
```php
$hooks->has('pre-receive'); // a boolean indicating presence
```
Inserting hooks
---------------
You can modify a hook in two different ways: creating a new file or
using a symlink.
To create the hook using a symlink:
```php
$hooks->setSymlink('pre-receive', '/path/to/file-to-link');
```
If the hook already exist, a *LogicException* will be thrown. If an
error occured during symlink creation, a *RuntimeException* will be
thrown.
If you want to directly create a new file in hooks directory, use the
method *set*. This method will create a new file, put content in it and
make it executable:
```php
$content = <<<HOOK
#!/bin/bash
echo "Push is disabled"
exit 1
HOOK;
// this hook will reject every push
$hooks->set('pre-receive', $content);
```
If the hook already exists, a *LogicException* will be thrown.
Removing hooks
--------------
To remove a hook from a repository, use the function *remove*:
```php
$hooks->remove('pre-receive');
```

View File

@@ -1,59 +0,0 @@
gitlib - library to manipulate git
==================================
gitlib requires PHP 5.3 and class autoloading (PSR-0) to work properly. Internally, it relies on ``git`` method calls
to fetch informations from repository.
.. code-block:: php
use Gitonomy\Git\Repository;
$repository = new Repository('/path/to/repository');
foreach ($repository->getReferences()->getBranches() as $branch) {
echo "- ".$branch->getName();
}
$repository->run('fetch', array('--all'));
Reference
---------
.. toctree::
:maxdepth: 1
api/admin
api/repository
api/hooks
api/workingcopy
api/commit
api/blame
api/blob
api/branch
api/tree
api/log
api/diff
api/references
api/revision
Documentation
-------------
.. toctree::
:maxdepth: 2
installation
debug
development
Missing features
----------------
Some major features are still missing from gitlib:
* Remotes
* Submodules
If you want to run git commands on repository, call method ``Repository::run`` with method and arguments.

View File

@@ -1,20 +0,0 @@
Installation of gitlib
======================
Autoloading
:::::::::::
gitlib relies on class autoloading. It does not require any additional setup.
Using composer
::::::::::::::
Edit your ``composer.json`` file and add ``gitonomy/gitlib`` in section ``require``:
.. code-block:: json
{
"require": {
"gitonomy/gitlib": "^1.0"
}
}

55
vendor/gitonomy/gitlib/doc/log.md vendored Normal file
View File

@@ -0,0 +1,55 @@
Getting log history
===================
Crawling manually commits and parents to browse history is surely a good
solution. But when it comes to ordering them or aggregate them from
multiple branches, we tend to use `git log`.
To get a *Log* object from a repository:
```php
$log = $repository->getLog();
```
You can pass four arguments to *getLog* method:
```php
// Global log for repository
$log = $repository->getLog();
// Log for master branch
$log = $repository->getLog('master');
// Returns last 10 commits on README file
$log = $repository->getLog('master', 'README', 0, 10);
// Returns last 10 commits on README or UPGRADE files
$log = $repository->getLog('master', ['README', 'UPGRADE'], 0, 10);
```
Counting
--------
If you want to count overall commits, without offset or limit, use the
*countCommits* method:
```php
echo sprintf('This log contains %s commits%s', $log->countCommits(), PHP_EOL);
// Countable interface
echo sprintf('This log contains %s commits%s', count($log), PHP_EOL);
```
Offset and limit
----------------
Use those methods:
```php
$log->setOffset(32);
$log->setLimit(40);
// or read it:
$log->getOffset();
$log->getLimit();
```

View File

@@ -0,0 +1,92 @@
Tags and branches
=================
Accessing tags and branches
---------------------------
With *gitlib*, you can access them via the *ReferenceBag* object. To get
this object from a *Repository*, use the *getReferences* method:
```php
$references = $repository->getReferences();
```
First, you can test existence of tags and branches like this:
```php
if ($references->hasBranch('master') && $references->hasTag('0.1')) {
echo 'Good start!'.PHP_EOL;
}
```
If you want to access all branches or all tags:
```php
$branches = $references->getBranches();
$localBranches = $references->getLocalBranches();
$remoteBranches = $references->getRemoteBranches();
$tags = $references->getTags();
$all = $references->getAll();
```
To get a given branch or tag, call *getBranch* or *getTag* on the
*ReferenceBag*. Those methods return *Branch* and *Tag* objects:
```php
$master = $references->getBranch('master');
$feat123 = $references->getLocalBranch('feat123');
$feat456 = $references->getRemoteBranch('origin/feat456');
$v0_1 = $references->getTag('0.1');
```
If the reference cannot be resolved, a *ReferenceNotFoundException* will
be thrown.
On each of those objects, you can access those informations:
```php
// Get the associated commit
$commit = $master->getCommit();
// Get the commit hash
$hash = $master->getCommitHash();
// Get the last modification
$lastModification = $master->getLastModification();
```
Create and delete reference
---------------------------
You can create new tags and branches on repository, using helper methods
on ReferenceBag object:
```php
// create a branch
$references = $repository->getReferences();
$branch = $references->createBranch('foobar', 'a8b7e4...'); // commit to reference
// create a tag
$references = $repository->getReferences();
$tag = $references->createTag('0.3', 'a8b7e4...'); // commit to reference
// delete a branch or a tag
$branch->delete();
```
Resolution from a commit
------------------------
To resolve a branch or a commit from a commit, you can use the
*resolveTags* and *resolveBranches* methods on it:
```php
$branches = $references->resolveBranches($commit);
$tags = $references->resolveTags($commit);
// Resolve branches and tags
$all = $references->resolve($commit);
```
You can pass a *Commit* object or a hash to the method, gitlib will
handle it.

147
vendor/gitonomy/gitlib/doc/repository.md vendored Normal file
View File

@@ -0,0 +1,147 @@
Repository methods
==================
Creating a *Repository* object is possible, providing a *path* argument
to the constructor:
```php
$repository = new Repository('/path/to/repo');
```
Repository options
------------------
The constructor of Repository takes an additional parameter: `$options`.
This parameter can be used used to tune behavior of library.
Available options are:
- **debug** (default: true): Enables exception when edge cases are met
- **environment\_variables**: (default: none) An array of environment
variables to be set in sub-process
- **logger**: (default: none) Logger to use for reporting of execution
(a `Psr\Log\LoggerInterface`)
- **command**: (default: `git`) Specify command to execute to run git
- **working\_dir**: If you are using multiple working directories,
this option is for you
An example:
```php
$repository = new Repository('/path/to/repo', [
'debug' => true,
'logger' => new Monolog\Logger(),
]);
```
Test if a repository is bare
----------------------------
On a *Repository* object, you can call method *isBare* to test if your
repository is bare or not:
```php
$repository->isBare();
```
Compute size of a repository
----------------------------
To know how much size a repository is using on your drive, you can use
`getSize` method on a *Repository* object.
> **warning**
>
> This command was only tested with linux.
The returned size is in kilobytes:
```php
$size = $repository->getSize();
echo 'Your repository size is '.$size.'KB';
```
Access HEAD
-----------
`HEAD` represents in git the version you are working on (in working
tree). Your `HEAD` can be attached (using a reference) or detached
(using a commit).
```php
$head = $repository->getHead(); // Commit or Reference
$head = $repository->getHeadCommit(); // Commit
if ($repository->isHeadDetached()) {
echo 'Sorry man'.PHP_EOL;
}
```
Options for repository
----------------------
### Logger
If you are developing, you may appreciate to have a logger inside
repository, telling you every executed command.
You call method `setLogger` as an option on repository creation:
```php
$repository->setLogger(new Monolog\Logger('repository'));
$repository->run('fetch', ['--all']);
```
You can also specify as an option on repository creation:
```php
$logger = new MonologLogger('repository');
$repository = new Repository('/path/foo', ['logger' => $logger]);
$repository->run('fetch', ['--all']);
```
This will output:
```
info run command: fetch "--all"
debug last command (fetch) duration: 23.24ms
debug last command (fetch) return code: 0
debug last command (fetch) output: Fetching origin
```
### Disable debug-mode
Gitlib throws an exception when something seems wrong. If a `git` command exits
with a non-zero code, then execution will be stopped, and a `RuntimeException`
will be thrown. If you want to prevent this, set the `debug` option to` false`.
This will make `Repository` log errors and return empty data instead of
throwing exceptions.
```php
$repository = new Repository('/tmp/foo', ['debug' => false, 'logger' => $logger]);
```
> **note**
>
> If you plan to disable debug, you should rely on the logger to keep a trace
> of the failing cases.
### Specify git command to use
You can pass the option `command` to specify which command to use to run git
calls. If you have a git binary located somewhere else, use this option to
specify to gitlib path to your git binary:
```php
$repository = new Gitonomy\Git\Repository('/tmp/foo', ['command' => '/home/alice/bin/git']);
```
### Environment variables
It is possible to send environment variables to the `git` commands.
```php
$repository = new Gitonomy\Git\Repository('/tmp/foo', ['environment_variables' => ['GIT_']])
```

28
vendor/gitonomy/gitlib/doc/revision.md vendored Normal file
View File

@@ -0,0 +1,28 @@
Revision
========
To get a revision from a *Repository* object:
```php
$revision = $repository->getRevision('master@{2 days ago}');
```
Getting the log
---------------
You can access a *Log* object starting from a revision using the
*getLog* method. This method takes two parameters: *offset* and *limit*:
```php
// Returns 100 lasts commits
$log = $revision->getLog(null, 100);
```
Resolve a revision
------------------
To resolve a revision to a commit:
```php
$commit = $revision->getCommit();
```

54
vendor/gitonomy/gitlib/doc/tree.md vendored Normal file
View File

@@ -0,0 +1,54 @@
Tree and files
==============
To organize folders, git uses trees. In gitlib, those trees are
represented via *Tree* object.
To get the root tree associated to a commit, use the *getTree* method on
the commit object:
```php
$tree = $commit->getTree();
```
This tree is the entry point of all of your files.
The main method for a tree is the *getEntries* method. This method will
return an array, indexed by name. Each of those elements will be the
entry mode and the entry object.
Let's understand how it works with a concrete example:
```php
function displayTree(Tree $tree, $indent = 0)
{
$indent = str_repeat(' ', $indent);
foreach ($tree->getEntries() as $name => $data) {
list($mode, $entry) = $data;
if ($entry instanceof Tree) {
echo $indent.$name.'/'.PHP_EOL;
displayTree($tree, $indent + 1);
} else {
echo $indent.$name.PHP_EOL;
}
}
}
displayTree($commit->getTree());
```
This method will recursively display all entries of a tree.
Resolve a path
--------------
To access directly a sub-file, the easier is probably to use the
*resolvePath* method.
An example:
```php
$source = $tree->resolvePath('src/Gitonomy/Git');
$source instanceof Tree;
```

View File

@@ -0,0 +1,47 @@
Working copy
============
Working copy is the folder associated to a git repository. In *gitlib*,
you can access this object using the *getWorkingCopy* on a *Repository*
object:
```php
$repo = new Repository('/path/to/working-dir');
$wc = $repo->getWorkingCopy();
```
Checkout a revision
-------------------
You can checkout any revision using *checkout* method. You can also pass
a second argument, which will be passed as argument with `-b`:
```php
// git checkout master
$wc->checkout('master');
// git checkout origin/master -b master
$wc->checkout('origin/master', 'master');
```
You can also pass a *Reference* or a *Commit*.
Staged modifications
--------------------
You can get a diff of modifications pending in staging area. To get the
`Diff` object, call method `getDiffStaged()`:
```php
$diff = $wc->getDiffStaged();
```
Pending modifications
---------------------
You can get pending modifications on tracked files by calling method
`getDiffPending()`:
```php
$diff = $wc->getDiffPending();
```

View File

@@ -1,21 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "tests/bootstrap.php" >
<phpunit backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
bootstrap="tests/bootstrap.php"
colors="true"
convertDeprecationsToExceptions="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
failOnRisky="true"
failOnWarning="false"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
verbose="true"
>
<testsuites>
<testsuite name="Test Suite">
<directory>tests/Gitonomy/Git/Tests</directory>
<directory suffix="Test.php">./tests/Gitonomy/Git/Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/Gitonomy/Git</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\RuntimeException;
@@ -28,13 +29,13 @@ class Admin
* @param bool $bare indicate to create a bare repository
* @param array $options options for Repository creation
*
* @return Repository
*
* @throws RuntimeException Directory exists or not writable (only if debug=true)
*
* @return Repository
*/
public static function init($path, $bare = true, array $options = array())
public static function init($path, $bare = true, array $options = [])
{
$process = static::getProcess('init', array_merge(array('-q'), $bare ? array('--bare') : array(), array($path)), $options);
$process = static::getProcess('init', array_merge(['-q'], $bare ? ['--bare'] : [], [$path]), $options);
$process->run();
@@ -57,9 +58,9 @@ class Admin
*
* @return bool true if url is valid
*/
public static function isValidRepository($url, array $options = array())
public static function isValidRepository($url, array $options = [])
{
$process = static::getProcess('ls-remote', array($url), $options);
$process = static::getProcess('ls-remote', [$url], $options);
$process->run();
@@ -76,9 +77,9 @@ class Admin
*
* @return Repository
*/
public static function cloneTo($path, $url, $bare = true, array $options = array())
public static function cloneTo($path, $url, $bare = true, array $options = [])
{
$args = $bare ? array('--bare') : array();
$args = $bare ? ['--bare'] : [];
return static::cloneRepository($path, $url, $args, $options);
}
@@ -94,9 +95,9 @@ class Admin
*
* @return Repository
*/
public static function cloneBranchTo($path, $url, $branch, $bare = true, $options = array())
public static function cloneBranchTo($path, $url, $branch, $bare = true, $options = [])
{
$args = array('--branch', $branch);
$args = ['--branch', $branch];
if ($bare) {
$args[] = '--bare';
}
@@ -113,9 +114,9 @@ class Admin
*
* @return Repository
*/
public static function mirrorTo($path, $url, array $options = array())
public static function mirrorTo($path, $url, array $options = [])
{
return static::cloneRepository($path, $url, array('--mirror'), $options);
return static::cloneRepository($path, $url, ['--mirror'], $options);
}
/**
@@ -128,9 +129,9 @@ class Admin
*
* @return Repository
*/
public static function cloneRepository($path, $url, array $args = array(), array $options = array())
public static function cloneRepository($path, $url, array $args = [], array $options = [])
{
$process = static::getProcess('clone', array_merge(array('-q'), $args, array($url, $path)), $options);
$process = static::getProcess('clone', array_merge(['-q'], $args, [$url, $path]), $options);
$process->run();
@@ -144,26 +145,16 @@ class Admin
/**
* This internal method is used to create a process object.
*/
private static function getProcess($command, array $args = array(), array $options = array())
private static function getProcess($command, array $args = [], array $options = [])
{
$is_windows = defined('PHP_WINDOWS_VERSION_BUILD');
$options = array_merge(array(
'environment_variables' => $is_windows ? array('PATH' => getenv('PATH')) : array(),
'command' => 'git',
'process_timeout' => 3600,
), $options);
$options = array_merge([
'environment_variables' => $is_windows ? ['PATH' => getenv('PATH')] : [],
'command' => 'git',
'process_timeout' => 3600,
], $options);
$commandline = array_merge(array($options['command'], $command), $args);
// Backward compatible layer for Symfony Process < 4.0.
if (class_exists('Symfony\Component\Process\ProcessBuilder')) {
$commandline = implode(' ', array_map(
'Symfony\Component\Process\ProcessUtils::escapeArgument',
$commandline
));
}
$process = new Process($commandline);
$process = new Process(array_merge([$options['command'], $command], $args));
$process->setEnv($options['environment_variables']);
$process->setTimeout($options['process_timeout']);
$process->setIdleTimeout($options['process_timeout']);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Blame\Line;
@@ -83,33 +84,31 @@ class Blame implements \Countable
*/
public function getGroupedLines()
{
$result = array();
$result = [];
$commit = null;
$current = array();
$current = [];
foreach ($this->getLines() as $lineNumber => $line) {
if ($commit !== $line->getCommit()) {
if (count($current)) {
$result[] = array($commit, $current);
$result[] = [$commit, $current];
}
$commit = $line->getCommit();
$current = array();
$current = [];
}
$current[$lineNumber] = $line;
}
if (count($current)) {
$result[] = array($commit, $current);
$result[] = [$commit, $current];
}
return $result;
}
/**
* Returns all lines of the blame.
*
* @return array
* @return Line[] All lines of the blame.
*/
public function getLines()
{
@@ -117,7 +116,7 @@ class Blame implements \Countable
return $this->lines;
}
$args = array('-p');
$args = ['-p'];
if (null !== $this->lineRange) {
$args[] = '-L';
@@ -138,6 +137,7 @@ class Blame implements \Countable
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->getLines());

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Blame;
use Gitonomy\Git\Commit;

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
/**
@@ -57,14 +58,14 @@ class Blob
}
/**
* Returns content of the blob.
*
* @throws ProcessException Error occurred while getting content of blob
*
* @return string Content of the blob.
*/
public function getContent()
{
if (null === $this->content) {
$this->content = $this->repository->run('cat-file', array('-p', $this->hash));
$this->content = $this->repository->run('cat-file', ['-p', $this->hash]);
}
return $this->content;

View File

@@ -9,12 +9,14 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Diff\Diff;
use Gitonomy\Git\Exception\InvalidArgumentException;
use Gitonomy\Git\Exception\ProcessException;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
use Gitonomy\Git\Reference\Branch;
use Gitonomy\Git\Util\StringHelper;
/**
@@ -29,15 +31,15 @@ class Commit extends Revision
*
* @var array
*/
private $data = array();
private $data = [];
/**
* Constructor.
*
* @param Gitonomy\Git\Repository $repository Repository of the commit
* @param string $hash Hash of the commit
* @param Repository $repository Repository of the commit
* @param string $hash Hash of the commit
*/
public function __construct(Repository $repository, $hash, array $data = array())
public function __construct(Repository $repository, $hash, array $data = [])
{
if (!preg_match('/^[a-f0-9]{40}$/', $hash)) {
throw new ReferenceNotFoundException($hash);
@@ -60,7 +62,7 @@ class Commit extends Revision
*/
public function getDiff()
{
$args = array('-r', '-p', '-m', '-M', '--no-commit-id', '--full-index', $this->revision);
$args = ['-r', '-p', '-m', '-M', '--no-commit-id', '--full-index', $this->revision];
$diff = Diff::parse($this->repository->run('diff-tree', $args));
$diff->setRepository($this->repository);
@@ -90,6 +92,8 @@ class Commit extends Revision
/**
* Returns a fixed-with short hash.
*
* @return string Short hash
*/
public function getFixedShortHash($length = 6)
{
@@ -99,7 +103,7 @@ class Commit extends Revision
/**
* Returns parent hashes.
*
* @return array An array of SHA1 hashes
* @return string[] An array of SHA1 hashes
*/
public function getParentHashes()
{
@@ -109,11 +113,11 @@ class Commit extends Revision
/**
* Returns the parent commits.
*
* @return array An array of Commit objects
* @return Commit[] An array of Commit objects
*/
public function getParents()
{
$result = array();
$result = [];
foreach ($this->getData('parentHashes') as $parentHash) {
$result[] = $this->repository->getCommit($parentHash);
}
@@ -131,6 +135,9 @@ class Commit extends Revision
return $this->getData('treeHash');
}
/**
* @return Tree
*/
public function getTree()
{
return $this->getData('tree');
@@ -149,7 +156,7 @@ class Commit extends Revision
$path = $getWorkingDir.'/'.$path;
}
$result = $this->repository->run('log', array('--format=%H', '-n', 1, $this->revision, '--', $path));
$result = $this->repository->run('log', ['--format=%H', '-n', 1, $this->revision, '--', $path]);
return $this->repository->getCommit(trim($result));
}
@@ -183,7 +190,7 @@ class Commit extends Revision
/**
* Resolves all references associated to this commit.
*
* @return array An array of references (Branch, Tag, Squash)
* @return Reference[] An array of references (Branch, Tag, Squash)
*/
public function resolveReferences()
{
@@ -196,11 +203,11 @@ class Commit extends Revision
* @param bool $local set true to try to locate a commit on local repository
* @param bool $remote set true to try to locate a commit on remote repository
*
* @return array An array of Reference\Branch
* @return Reference[]|Branch[] An array of Reference\Branch
*/
public function getIncludingBranches($local = true, $remote = true)
{
$arguments = array('--contains', $this->revision);
$arguments = ['--contains', $this->revision];
if ($local && $remote) {
$arguments[] = '-a';
@@ -213,20 +220,22 @@ class Commit extends Revision
try {
$result = $this->repository->run('branch', $arguments);
} catch (ProcessException $e) {
return array();
return [];
}
if (!$result) {
return array();
return [];
}
$branchesName = explode("\n", trim(str_replace('*', '', $result)));
$branchesName = array_filter($branchesName, function ($v) { return false === StringHelper::strpos($v, '->');});
$branchesName = array_filter($branchesName, function ($v) {
return false === StringHelper::strpos($v, '->');
});
$branchesName = array_map('trim', $branchesName);
$references = $this->repository->getReferences();
$branches = array();
$branches = [];
foreach ($branchesName as $branchName) {
if (false === $local) {
$branches[] = $references->getRemoteBranch($branchName);
@@ -263,7 +272,7 @@ class Commit extends Revision
/**
* Returns the authoring date.
*
* @return DateTime A time object
* @return \DateTime A time object
*/
public function getAuthorDate()
{
@@ -293,7 +302,7 @@ class Commit extends Revision
/**
* Returns the authoring date.
*
* @return DateTime A time object
* @return \DateTime A time object
*/
public function getCommitterDate()
{
@@ -331,7 +340,7 @@ class Commit extends Revision
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function getCommit()
{
@@ -345,7 +354,7 @@ class Commit extends Revision
}
if ($name === 'shortHash') {
$this->data['shortHash'] = trim($this->repository->run('log', array('--abbrev-commit', '--format=%h', '-n', 1, $this->revision)));
$this->data['shortHash'] = trim($this->repository->run('log', ['--abbrev-commit', '--format=%h', '-n', 1, $this->revision]));
return $this->data['shortHash'];
}
@@ -377,8 +386,9 @@ class Commit extends Revision
}
$parser = new Parser\CommitParser();
try {
$result = $this->repository->run('cat-file', array('commit', $this->revision));
$result = $this->repository->run('cat-file', ['commit', $this->revision]);
} catch (ProcessException $e) {
throw new ReferenceNotFoundException(sprintf('Can not find reference "%s"', $this->revision));
}

View File

@@ -9,10 +9,14 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
class CommitReference
{
/**
* @var string
*/
private $hash;
public function __construct($hash)

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Diff;
use Gitonomy\Git\Parser\DiffParser;
@@ -22,7 +23,7 @@ use Gitonomy\Git\Repository;
class Diff
{
/**
* @var array
* @var File[]
*/
protected $files;
@@ -61,18 +62,10 @@ class Diff
}
}
/**
* @return array
*/
public function getRevisions()
{
return $this->revisions;
}
/**
* Get list of files modified in the diff's revision.
*
* @return array An array of Diff\File objects
* @return File[] An array of Diff\File objects
*/
public function getFiles()
{
@@ -96,14 +89,15 @@ class Diff
*/
public function toArray()
{
return array(
return [
'rawDiff' => $this->rawDiff,
'files' => array_map(
'files' => array_map(
function (File $file) {
return $file->toArray();
}, $this->files
},
$this->files
),
);
];
}
/**
@@ -119,7 +113,8 @@ class Diff
array_map(
function ($array) {
return File::fromArray($array);
}, $array['files']
},
$array['files']
),
$array['rawDiff']
);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Diff;
use Gitonomy\Git\Repository;
@@ -54,7 +55,7 @@ class File
protected $isBinary;
/**
* @var array An array of FileChange objects
* @var FileChange[] An array of FileChange objects
*/
protected $changes;
@@ -76,7 +77,7 @@ class File
$this->newIndex = $newIndex;
$this->isBinary = $isBinary;
$this->changes = array();
$this->changes = [];
}
public function addChange(FileChange $change)
@@ -214,6 +215,9 @@ class File
return $this->isBinary;
}
/**
* @return FileChange[]
*/
public function getChanges()
{
return $this->changes;
@@ -221,20 +225,23 @@ class File
public function toArray()
{
return array(
'old_name' => $this->oldName,
'new_name' => $this->newName,
'old_mode' => $this->oldMode,
'new_mode' => $this->newMode,
return [
'old_name' => $this->oldName,
'new_name' => $this->newName,
'old_mode' => $this->oldMode,
'new_mode' => $this->newMode,
'old_index' => $this->oldIndex,
'new_index' => $this->newIndex,
'is_binary' => $this->isBinary,
'changes' => array_map(function (FileChange $change) {
'changes' => array_map(function (FileChange $change) {
return $change->toArray();
}, $this->changes),
);
];
}
/**
* @return File
*/
public static function fromArray(array $array)
{
$file = new self($array['old_name'], $array['new_name'], $array['old_mode'], $array['new_mode'], $array['old_index'], $array['new_index'], $array['is_binary']);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Diff;
class FileChange
@@ -23,6 +24,15 @@ class FileChange
protected $rangeNewCount;
protected $lines;
/**
* @param int $rangeOldStart
* @param int $rangeOldCount
* @param int $rangeNewStart
* @param int $rangeNewCount
* @param array $lines
*
* @return void
*/
public function __construct($rangeOldStart, $rangeOldCount, $rangeNewStart, $rangeNewCount, $lines)
{
$this->rangeOldStart = $rangeOldStart;
@@ -32,54 +42,80 @@ class FileChange
$this->lines = $lines;
}
/**
* @return int
*/
public function getCount($type)
{
$result = 0;
foreach ($this->lines as $line) {
if ($line[0] === $type) {
++$result;
$result++;
}
}
return $result;
}
/**
* @return int
*/
public function getRangeOldStart()
{
return $this->rangeOldStart;
}
/**
* @return int
*/
public function getRangeOldCount()
{
return $this->rangeOldCount;
}
/**
* @return int
*/
public function getRangeNewStart()
{
return $this->rangeNewStart;
}
/**
* @return int
*/
public function getRangeNewCount()
{
return $this->rangeNewCount;
}
/**
* @return array
*/
public function getLines()
{
return $this->lines;
}
/**
* @return array
*/
public function toArray()
{
return array(
return [
'range_old_start' => $this->rangeOldStart,
'range_old_count' => $this->rangeOldCount,
'range_new_start' => $this->rangeNewStart,
'range_new_count' => $this->rangeNewCount,
'lines' => $this->lines,
);
'lines' => $this->lines,
];
}
/**
* @param array $array
*
* @return self
*/
public static function fromArray(array $array)
{
return new self($array['range_old_start'], $array['range_old_count'], $array['range_new_start'], $array['range_new_count'], $array['lines']);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Exception;
interface GitExceptionInterface

View File

@@ -10,7 +10,8 @@ class ProcessException extends RuntimeException implements GitExceptionInterface
public function __construct(Process $process)
{
parent::__construct("Error while running git command:\n".
parent::__construct(
"Error while running git command:\n".
$process->getCommandLine()."\n".
"\n".
$process->getErrorOutput()."\n".

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Exception;
class ReferenceNotFoundException extends \InvalidArgumentException implements GitExceptionInterface

View File

@@ -9,10 +9,12 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\InvalidArgumentException;
use Gitonomy\Git\Exception\LogicException;
use Gitonomy\Git\Exception\RuntimeException;
/**
* Hooks collection, aggregated by repository.
@@ -22,7 +24,7 @@ use Gitonomy\Git\Exception\LogicException;
class Hooks
{
/**
* @var Gitonomy\Git\Repository
* @var \Gitonomy\Git\Repository
*/
protected $repository;
@@ -51,9 +53,9 @@ class Hooks
*
* @param string $name Name of the hook
*
* @return string Content of the hook
*
* @throws InvalidArgumentException Hook does not exist
*
* @return string Content of the hook
*/
public function get($name)
{
@@ -81,7 +83,7 @@ class Hooks
$path = $this->getPath($name);
if (false === symlink($file, $path)) {
throw new RuntimeException(sprintf('Unable to create hook "%s"', $name, $path));
throw new RuntimeException(sprintf('Unable to create hook "%s" (%s)', $name, $path));
}
}
@@ -120,6 +122,9 @@ class Hooks
unlink($this->getPath($name));
}
/**
* @return string
*/
protected function getPath($name)
{
return $this->repository->getGitDir().'/hooks/'.$name;

View File

@@ -9,8 +9,10 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Diff\Diff;
use Gitonomy\Git\Exception\ProcessException;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
use Gitonomy\Git\Util\StringHelper;
@@ -61,9 +63,9 @@ class Log implements \Countable, \IteratorAggregate
}
if (null === $paths) {
$paths = array();
$paths = [];
} elseif (is_string($paths)) {
$paths = array($paths);
$paths = [$paths];
} elseif (!is_array($paths)) {
throw new \InvalidArgumentException(sprintf('Expected a string or an array, got a "%s".', is_object($paths) ? get_class($paths) : gettype($paths)));
}
@@ -135,6 +137,9 @@ class Log implements \Countable, \IteratorAggregate
return $this;
}
/**
* @return Commit
*/
public function getSingleCommit()
{
$limit = $this->limit;
@@ -150,11 +155,11 @@ class Log implements \Countable, \IteratorAggregate
}
/**
* @return array
* @return Commit[]
*/
public function getCommits()
{
$args = array('--encoding='.StringHelper::getEncoding(), '--format=raw');
$args = ['--encoding='.StringHelper::getEncoding(), '--format=raw'];
if (null !== $this->offset) {
$args[] = '--skip='.((int) $this->offset);
@@ -184,7 +189,7 @@ class Log implements \Countable, \IteratorAggregate
$parser = new Parser\LogParser();
$parser->parse($output);
$result = array();
$result = [];
foreach ($parser->log as $commitData) {
$hash = $commitData['id'];
unset($commitData['id']);
@@ -201,6 +206,7 @@ class Log implements \Countable, \IteratorAggregate
/**
* @see Countable
*/
#[\ReturnTypeWillChange]
public function count()
{
return $this->countCommits();
@@ -209,6 +215,7 @@ class Log implements \Countable, \IteratorAggregate
/**
* @see IteratorAggregate
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->getCommits());
@@ -222,9 +229,9 @@ class Log implements \Countable, \IteratorAggregate
public function countCommits()
{
if (null !== $this->revisions && count($this->revisions)) {
$output = $this->repository->run('rev-list', array_merge(array('--count'), $this->revisions->getAsTextArray(), array('--'), $this->paths));
$output = $this->repository->run('rev-list', array_merge(['--count'], $this->revisions->getAsTextArray(), ['--'], $this->paths));
} else {
$output = $this->repository->run('rev-list', array_merge(array('--count', '--all', '--'), $this->paths));
$output = $this->repository->run('rev-list', array_merge(['--count', '--all', '--'], $this->paths));
}
return (int) $output;

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
use Gitonomy\Git\Blame\Line;
@@ -27,9 +28,9 @@ class BlameParser extends ParserBase
protected function doParse()
{
$this->lines = array();
$this->lines = [];
$memory = array();
$memory = [];
$line = 1;
while (!$this->isFinished()) {
@@ -43,9 +44,9 @@ class BlameParser extends ParserBase
$this->consumeNewLine();
if (!isset($memory[$hash])) {
foreach (array('author', 'author-mail', 'author-time', 'author-tz',
foreach (['author', 'author-mail', 'author-time', 'author-tz',
'committer', 'committer-mail', 'committer-time', 'committer-tz',
'summary', ) as $key) {
'summary', ] as $key) {
$this->consume($key);
$this->consumeTo("\n");
$this->consumeNewLine();
@@ -68,7 +69,7 @@ class BlameParser extends ParserBase
$this->consumeNewLine();
$this->lines[$line] = new Line($memory[$hash], $sourceLine, $targetLine, $blockLine, $content);
++$line;
$line++;
}
}
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
use Gitonomy\Git\Exception\RuntimeException;
@@ -31,7 +32,7 @@ class CommitParser extends ParserBase
$this->tree = $this->consumeHash();
$this->consumeNewLine();
$this->parents = array();
$this->parents = [];
while ($this->expects('parent ')) {
$this->parents[] = $this->consumeHash();
$this->consumeNewLine();
@@ -63,7 +64,7 @@ class CommitParser extends ParserBase
$this->cursor += strlen($vars[1]);
return array($vars[2], $vars[3], $vars[4]);
return [$vars[2], $vars[3], $vars[4]];
}
protected function parseDate($text)

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
use Gitonomy\Git\Diff\File;
@@ -20,11 +21,11 @@ class DiffParser extends ParserBase
protected function doParse()
{
$this->files = array();
$this->files = [];
while (!$this->isFinished()) {
// 1. title
$vars = $this->consumeRegexp('/diff --git (a\/.*) (b\/.*)\n/');
$vars = $this->consumeRegexp("/diff --git \"?(a\/.*?)\"? \"?(b\/.*?)\"?\n/");
$oldName = $vars[1];
$newName = $vars[2];
$oldIndex = null;
@@ -73,14 +74,15 @@ class DiffParser extends ParserBase
}
$this->consumeNewLine();
//verifying if the file was deleted or created
if ($this->expects('--- ')) {
$oldName = $this->consumeTo("\n");
$oldName = $this->consumeTo("\n") === '/dev/null' ? '/dev/null' : $oldName;
$this->consumeNewLine();
$this->consume('+++ ');
$newName = $this->consumeTo("\n");
$newName = $this->consumeTo("\n") === '/dev/null' ? '/dev/null' : $newName;
$this->consumeNewLine();
} elseif ($this->expects('Binary files ')) {
$vars = $this->consumeRegexp('/(.*) and (.*) differ\n/');
$vars = $this->consumeRegexp('/"?(.*?)"? and "?(.*?)"? differ\n/');
$isBinary = true;
$oldName = $vars[1];
$newName = $vars[2];
@@ -89,6 +91,9 @@ class DiffParser extends ParserBase
$oldName = $oldName === '/dev/null' ? null : substr($oldName, 2);
$newName = $newName === '/dev/null' ? null : substr($newName, 2);
$oldIndex = $oldIndex !== null ?: '';
$newIndex = $newIndex !== null ?: '';
$oldIndex = preg_match('/^0+$/', $oldIndex) ? null : $oldIndex;
$newIndex = preg_match('/^0+$/', $newIndex) ? null : $newIndex;
$file = new File($oldName, $newName, $oldMode, $newMode, $oldIndex, $newIndex, $isBinary);
@@ -96,23 +101,23 @@ class DiffParser extends ParserBase
// 5. Diff
while ($this->expects('@@ ')) {
$vars = $this->consumeRegexp('/-(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/');
$rangeOldStart = $vars[1];
$rangeOldCount = $vars[2];
$rangeNewStart = $vars[3];
$rangeNewCount = isset($vars[4]) ? $vars[4] : $vars[2]; // @todo Ici, t'as pris un gros raccourci mon loulou
$rangeOldStart = (int) $vars[1];
$rangeOldCount = (int) $vars[2];
$rangeNewStart = (int) $vars[3];
$rangeNewCount = isset($vars[4]) ? (int) $vars[4] : (int) $vars[2]; // @todo Ici, t'as pris un gros raccourci mon loulou
$this->consume(' @@');
$this->consumeTo("\n");
$this->consumeNewLine();
// 6. Lines
$lines = array();
$lines = [];
while (true) {
if ($this->expects(' ')) {
$lines[] = array(FileChange::LINE_CONTEXT, $this->consumeTo("\n"));
$lines[] = [FileChange::LINE_CONTEXT, $this->consumeTo("\n")];
} elseif ($this->expects('+')) {
$lines[] = array(FileChange::LINE_ADD, $this->consumeTo("\n"));
$lines[] = [FileChange::LINE_ADD, $this->consumeTo("\n")];
} elseif ($this->expects('-')) {
$lines[] = array(FileChange::LINE_REMOVE, $this->consumeTo("\n"));
$lines[] = [FileChange::LINE_REMOVE, $this->consumeTo("\n")];
} elseif ($this->expects("\ No newline at end of file")) {
// Ignore this case...
} else {

View File

@@ -9,18 +9,19 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
class LogParser extends CommitParser
{
public $log = array();
public $log = [];
protected function doParse()
{
$this->log = array();
$this->log = [];
while (!$this->isFinished()) {
$commit = array();
$commit = [];
$this->consume('commit ');
$commit['id'] = $this->consumeHash();
$this->consumeNewLine();
@@ -29,7 +30,7 @@ class LogParser extends CommitParser
$commit['treeHash'] = $this->consumeHash();
$this->consumeNewLine();
$commit['parentHashes'] = array();
$commit['parentHashes'] = [];
while ($this->expects('parent ')) {
$commit['parentHashes'][] = $this->consumeHash();
$this->consumeNewLine();
@@ -58,8 +59,7 @@ class LogParser extends CommitParser
$message .= $this->consumeTo("\n")."\n";
$this->consumeNewLine();
}
}
else {
} else {
$this->cursor--;
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
use Gitonomy\Git\Exception\RuntimeException;
@@ -58,7 +59,7 @@ abstract class ParserBase
protected function consumeShortHash()
{
if (!preg_match('/([A-Za-z0-9]{7,40})/A', $this->content, $vars, null, $this->cursor)) {
if (!preg_match('/([A-Za-z0-9]{7,40})/A', $this->content, $vars, 0, $this->cursor)) {
throw new RuntimeException('No short hash found: '.substr($this->content, $this->cursor, 7));
}
@@ -69,7 +70,7 @@ abstract class ParserBase
protected function consumeHash()
{
if (!preg_match('/([A-Za-z0-9]{40})/A', $this->content, $vars, null, $this->cursor)) {
if (!preg_match('/([A-Za-z0-9]{40})/A', $this->content, $vars, 0, $this->cursor)) {
throw new RuntimeException('No hash found: '.substr($this->content, $this->cursor, 40));
}
@@ -80,8 +81,8 @@ abstract class ParserBase
protected function consumeRegexp($regexp)
{
if (!preg_match($regexp.'A', $this->content, $vars, null, $this->cursor)) {
throw new RuntimeException('No match for regexp '.$regexp.' Upcoming: '.substr($this->content, $this->cursor, 30));
if (!preg_match($regexp.'A', $this->content, $vars, 0, $this->cursor)) {
throw new RuntimeException('No match for regexp '.$regexp.' Upcoming: '.substr($this->content, $this->cursor, 500));
}
$this->cursor += strlen($vars[0]);
@@ -123,11 +124,12 @@ abstract class ParserBase
/**
* @return string
*/
protected function consumeGPGSignature() {
protected function consumeGPGSignature()
{
$expected = "\ngpgsig ";
$length = strlen($expected);
$actual = substr($this->content, $this->cursor, $length);
if($actual != $expected) {
if ($actual != $expected) {
return '';
}
$this->cursor += $length;

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
class ReferenceParser extends ParserBase
@@ -17,14 +18,14 @@ class ReferenceParser extends ParserBase
protected function doParse()
{
$this->references = array();
$this->references = [];
while (!$this->isFinished()) {
$hash = $this->consumeHash();
$this->consume(' ');
$name = $this->consumeTo("\n");
$this->consumeNewLine();
$this->references[] = array($hash, $name);
$this->references[] = [$hash, $name];
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* This file is part of Gitonomy.
*
* (c) Alexandre Salomé <alexandre.salome@gmail.com>
* (c) Julien DIDIER <genzo.wm@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
use Gitonomy\Git\Exception\RuntimeException;
class TagParser extends ParserBase
{
public $object;
public $type;
public $tag;
public $taggerName;
public $taggerEmail;
public $taggerDate;
public $gpgSignature;
public $message;
protected function doParse()
{
$this->consume('object ');
$this->object = $this->consumeHash();
$this->consumeNewLine();
$this->consume('type ');
$this->type = $this->consumeTo("\n");
$this->consumeNewLine();
$this->consume('tag ');
$this->tag = $this->consumeTo("\n");
$this->consumeNewLine();
$this->consume('tagger ');
list($this->taggerName, $this->taggerEmail, $this->taggerDate) = $this->consumeNameEmailDate();
$this->taggerDate = $this->parseDate($this->taggerDate);
$this->consumeNewLine();
$this->consumeNewLine();
try {
$this->message = $this->consumeTo('-----BEGIN PGP SIGNATURE-----');
$this->gpgSignature = $this->consumeGPGSignature();
} catch (RuntimeException $e) {
$this->message = $this->consumeAll();
}
}
protected function consumeGPGSignature()
{
$expected = '-----BEGIN PGP SIGNATURE-----';
$length = strlen($expected);
$actual = substr($this->content, $this->cursor, $length);
if ($actual != $expected) {
return '';
}
$this->cursor += $length;
return $this->consumeTo('-----END PGP SIGNATURE-----');
}
protected function consumeNameEmailDate()
{
if (!preg_match('/(([^\n]*) <([^\n]*)> (\d+ [+-]\d{4}))/A', $this->content, $vars, 0, $this->cursor)) {
throw new RuntimeException('Unable to parse name, email and date');
}
$this->cursor += strlen($vars[1]);
return [$vars[2], $vars[3], $vars[4]];
}
protected function parseDate($text)
{
$date = \DateTime::createFromFormat('U e O', $text.' UTC');
if (!$date instanceof \DateTime) {
throw new RuntimeException(sprintf('Unable to convert "%s" to datetime', $text));
}
return $date;
}
}

View File

@@ -9,11 +9,12 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Parser;
class TreeParser extends ParserBase
{
public $entries = array();
public $entries = [];
protected function doParse()
{
@@ -32,7 +33,7 @@ class TreeParser extends ParserBase
$name = $this->consumeTo("\n");
$this->consumeNewLine();
$this->entries[] = array($mode, $type, $hash, $name);
$this->entries[] = [$mode, $type, $hash, $name];
}
}
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\LogicException;
@@ -23,6 +24,10 @@ class PushReference
{
const ZERO = '0000000000000000000000000000000000000000';
/**
* @var Repository
*/
protected $repository;
/**
* @var string
*/
@@ -85,18 +90,21 @@ class PushReference
}
/**
* @return array
* @return Log
*/
public function getLog($excludes = array())
public function getLog($excludes = [])
{
return $this->repository->getLog(array_merge(
array($this->getRevision()),
[$this->getRevision()],
array_map(function ($e) {
return '^'.$e;
}, $excludes)
));
}
/**
* @return string
*/
public function getRevision()
{
if ($this->isDelete()) {
@@ -159,10 +167,10 @@ class PushReference
return false;
}
$result = $this->repository->run('merge-base', array(
$result = $this->repository->run('merge-base', [
$this->before,
$this->after,
));
]);
return $this->before !== trim($result);
}

View File

@@ -9,8 +9,12 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\ProcessException;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
/**
* Reference in a Git repository.
*
@@ -28,16 +32,25 @@ abstract class Reference extends Revision
$this->commitHash = $commitHash;
}
/**
* @return string
*/
public function getFullname()
{
return $this->revision;
}
/**
* @return void
*/
public function delete()
{
$this->repository->getReferences()->delete($this->getFullname());
}
/**
* @return string
*/
public function getCommitHash()
{
if (null !== $this->commitHash) {
@@ -45,7 +58,7 @@ abstract class Reference extends Revision
}
try {
$result = $this->repository->run('rev-parse', array('--verify', $this->revision));
$result = $this->repository->run('rev-parse', ['--verify', $this->revision]);
} catch (ProcessException $e) {
throw new ReferenceNotFoundException(sprintf('Can not find revision "%s"', $this->revision));
}
@@ -54,15 +67,16 @@ abstract class Reference extends Revision
}
/**
* Returns the commit associated to the reference.
*
* @return Commit
* @return Commit Commit associated to the reference.
*/
public function getCommit()
{
return $this->repository->getCommit($this->getCommitHash());
}
/**
* @return Commit
*/
public function getLastModification($path = null)
{
return $this->getCommit()->getLastModification($path);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Reference;
use Gitonomy\Git\Exception\RuntimeException;

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Reference;
use Gitonomy\Git\Reference;

View File

@@ -9,18 +9,26 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Reference;
use Gitonomy\Git\Commit;
use Gitonomy\Git\Exception\ProcessException;
use Gitonomy\Git\Exception\RuntimeException;
use Gitonomy\Git\Parser\ReferenceParser;
use Gitonomy\Git\Parser\TagParser;
use Gitonomy\Git\Reference;
/**
* Representation of a tag reference.
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
* @author Bruce Wells <brucekwells@gmail.com>
*/
class Tag extends Reference
{
protected $data;
public function getName()
{
if (!preg_match('#^refs/tags/(.*)$#', $this->revision, $vars)) {
@@ -29,4 +37,180 @@ class Tag extends Reference
return $vars[1];
}
/**
* Check if tag is annotated.
*
* @return bool
*/
public function isAnnotated()
{
try {
$this->repository->run('cat-file', ['tag', $this->revision]);
} catch (ProcessException $e) {
return false; // Is not an annotated tag
}
return true;
}
/**
* Returns the actual commit associated with the tag, and not the hash of the tag if annotated.
*
* @return Commit
*/
public function getCommit()
{
if ($this->isAnnotated()) {
try {
$output = $this->repository->run('show-ref', ['-d', '--tag', $this->revision]);
$parser = new ReferenceParser();
$parser->parse($output);
foreach ($parser->references as list($row)) {
$commitHash = $row;
}
return $this->repository->getCommit($commitHash);
} catch (ProcessException $e) {
// ignore the exception
}
}
return parent::getCommit();
}
/**
* Returns the tagger name.
*
* @return string A name
*/
public function getTaggerName()
{
return $this->getData('taggerName');
}
/**
* Returns the comitter email.
*
* @return string An email
*/
public function getTaggerEmail()
{
return $this->getData('taggerEmail');
}
/**
* Returns the authoring date.
*
* @return \DateTime A time object
*/
public function getTaggerDate()
{
return $this->getData('taggerDate');
}
/**
* Returns the message of the commit.
*
* @return string A tag message
*/
public function getMessage()
{
return $this->getData('message');
}
/**
* Returns the subject message (the first line).
*
* @return string The subject message
*/
public function getSubjectMessage()
{
return $this->getData('subjectMessage');
}
/**
* Return the body message.
*
* @return string The body message
*/
public function getBodyMessage()
{
return $this->getData('bodyMessage');
}
/**
* Return the GPG signature.
*
* @return string The GPG signature
*/
public function getGPGSignature()
{
return $this->getData('gpgSignature');
}
/**
* Check whether tag is signed.
*
* @return bool
*/
public function isSigned()
{
try {
$this->getGPGSignature();
return true;
} catch (\InvalidArgumentException $e) {
return false;
}
}
private function getData($name)
{
if (!$this->isAnnotated()) {
return false;
}
if (isset($this->data[$name])) {
return $this->data[$name];
}
if ($name === 'subjectMessage') {
$lines = explode("\n", $this->getData('message'));
$this->data['subjectMessage'] = reset($lines);
return $this->data['subjectMessage'];
}
if ($name === 'bodyMessage') {
$message = $this->getData('message');
$lines = explode("\n", $message);
array_shift($lines);
array_pop($lines);
$data['bodyMessage'] = implode("\n", $lines);
return $data['bodyMessage'];
}
$parser = new TagParser();
$result = $this->repository->run('cat-file', ['tag', $this->revision]);
$parser->parse($result);
$this->data['taggerName'] = $parser->taggerName;
$this->data['taggerEmail'] = $parser->taggerEmail;
$this->data['taggerDate'] = $parser->taggerDate;
$this->data['message'] = $parser->message;
$this->data['gpgSignature'] = $parser->gpgSignature;
if (!isset($this->data[$name])) {
throw new \InvalidArgumentException(sprintf('No data named "%s" in Tag.', $name));
}
return $this->data[$name];
}
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
@@ -28,7 +29,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
/**
* Repository object.
*
* @var Gitonomy\Git\Repository
* @var Repository
*/
protected $repository;
@@ -42,14 +43,14 @@ class ReferenceBag implements \Countable, \IteratorAggregate
/**
* List with all tags.
*
* @var array
* @var Tag[]
*/
protected $tags;
/**
* List with all branches.
*
* @var array
* @var Branch[]
*/
protected $branches;
@@ -63,14 +64,14 @@ class ReferenceBag implements \Countable, \IteratorAggregate
/**
* Constructor.
*
* @param Gitonomy\Git\Repository $repository The repository
* @param Repository $repository The repository
*/
public function __construct($repository)
{
$this->repository = $repository;
$this->references = array();
$this->tags = array();
$this->branches = array();
$this->references = [];
$this->tags = [];
$this->branches = [];
}
/**
@@ -91,6 +92,9 @@ class ReferenceBag implements \Countable, \IteratorAggregate
return $this->references[$fullname];
}
/**
* @return bool
*/
public function has($fullname)
{
$this->initialize();
@@ -98,18 +102,24 @@ class ReferenceBag implements \Countable, \IteratorAggregate
return isset($this->references[$fullname]);
}
/**
* @return Reference
*/
public function update(Reference $reference)
{
$fullname = $reference->getFullname();
$this->initialize();
$this->repository->run('update-ref', array($fullname, $reference->getCommitHash()));
$this->repository->run('update-ref', [$fullname, $reference->getCommitHash()]);
$this->references[$fullname] = $reference;
return $reference;
}
/**
* @return Reference
*/
public function createBranch($name, $commitHash)
{
$branch = new Branch($this->repository, 'refs/heads/'.$name, $commitHash);
@@ -117,6 +127,9 @@ class ReferenceBag implements \Countable, \IteratorAggregate
return $this->update($branch);
}
/**
* @return Reference
*/
public function createTag($name, $commitHash)
{
$tag = new Tag($this->repository, 'refs/tags/'.$name, $commitHash);
@@ -124,13 +137,19 @@ class ReferenceBag implements \Countable, \IteratorAggregate
return $this->update($tag);
}
/**
* @return void
*/
public function delete($fullname)
{
$this->repository->run('update-ref', array('-d', $fullname));
$this->repository->run('update-ref', ['-d', $fullname]);
unset($this->references[$fullname]);
}
/**
* @return bool
*/
public function hasBranches()
{
$this->initialize();
@@ -153,6 +172,9 @@ class ReferenceBag implements \Countable, \IteratorAggregate
return $this->has('refs/tags/'.$name);
}
/**
* @return Branch
*/
public function getFirstBranch()
{
$this->initialize();
@@ -162,7 +184,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* @return array An array of Tag objects
* @return Tag[] An array of Tag objects
*/
public function resolveTags($hash)
{
@@ -172,7 +194,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
$hash = $hash->getHash();
}
$tags = array();
$tags = [];
foreach ($this->references as $reference) {
if ($reference instanceof Reference\Tag && $reference->getCommitHash() === $hash) {
$tags[] = $reference;
@@ -183,7 +205,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* @return array An array of Branch objects
* @return Branch[] An array of Branch objects
*/
public function resolveBranches($hash)
{
@@ -193,7 +215,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
$hash = $hash->getHash();
}
$branches = array();
$branches = [];
foreach ($this->references as $reference) {
if ($reference instanceof Reference\Branch && $reference->getCommitHash() === $hash) {
$branches[] = $reference;
@@ -204,7 +226,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* @return array An array of references
* @return Reference[] An array of references
*/
public function resolve($hash)
{
@@ -214,7 +236,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
$hash = $hash->getHash();
}
$result = array();
$result = [];
foreach ($this->references as $k => $reference) {
if ($reference->getCommitHash() === $hash) {
$result[] = $reference;
@@ -225,9 +247,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* Returns all tags.
*
* @return array
* @return Tag[] All tags.
*/
public function getTags()
{
@@ -237,15 +257,13 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* Returns all branches.
*
* @return array
* @return Branch[] All branches.
*/
public function getBranches()
{
$this->initialize();
$result = array();
$result = [];
foreach ($this->references as $reference) {
if ($reference instanceof Reference\Branch) {
$result[] = $reference;
@@ -256,13 +274,11 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* Returns all locales branches.
*
* @return array
* @return Branch[] All local branches.
*/
public function getLocalBranches()
{
$result = array();
$result = [];
foreach ($this->getBranches() as $branch) {
if ($branch->isLocal()) {
$result[] = $branch;
@@ -273,13 +289,11 @@ class ReferenceBag implements \Countable, \IteratorAggregate
}
/**
* Returns all remote branches.
*
* @return array
* @return Branch[] All remote branches.
*/
public function getRemoteBranches()
{
$result = array();
$result = [];
foreach ($this->getBranches() as $branch) {
if ($branch->isRemote()) {
$result[] = $branch;
@@ -365,12 +379,6 @@ class ReferenceBag implements \Countable, \IteratorAggregate
} elseif ($fullname === 'refs/stash') {
$reference = new Stash($this->repository, $fullname, $commitHash);
$this->references[$fullname] = $reference;
} elseif (preg_match('#^refs/pull/(.*)$#', $fullname)) {
// Do nothing here
} elseif ($fullname === 'refs/notes/gtm-data') {
// Do nothing here
} else {
throw new RuntimeException(sprintf('Unable to parse "%s"', $fullname));
}
}
}
@@ -380,6 +388,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
*
* @see Countable
*/
#[\ReturnTypeWillChange]
public function count()
{
$this->initialize();
@@ -390,6 +399,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate
/**
* @see IteratorAggregate
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$this->initialize();

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Diff\Diff;
@@ -17,7 +18,6 @@ use Gitonomy\Git\Exception\ProcessException;
use Gitonomy\Git\Exception\RuntimeException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessUtils;
/**
* Git repository object.
@@ -86,6 +86,11 @@ class Repository
*/
protected $environmentVariables;
/**
* @var bool
*/
protected $inheritEnvironmentVariables;
/**
* Timeout that should be set for every running process.
*
@@ -111,17 +116,17 @@ class Repository
*
* @throws InvalidArgumentException The folder does not exists
*/
public function __construct($dir, $options = array())
public function __construct($dir, $options = [])
{
$is_windows = defined('PHP_WINDOWS_VERSION_BUILD');
$options = array_merge(array(
'working_dir' => null,
'debug' => true,
'logger' => null,
'environment_variables' => $is_windows ? array('PATH' => getenv('path')) : array(),
'command' => 'git',
'process_timeout' => 3600,
), $options);
$options = array_merge([
'working_dir' => null,
'debug' => true,
'logger' => null,
'command' => 'git',
'environment_variables' => [],
'inherit_environment_variables' => false,
'process_timeout' => 3600,
], $options);
if (null !== $options['logger'] && !$options['logger'] instanceof LoggerInterface) {
throw new InvalidArgumentException(sprintf('Argument "logger" passed to Repository should be a Psr\Log\LoggerInterface. A %s was provided', is_object($options['logger']) ? get_class($options['logger']) : gettype($options['logger'])));
@@ -130,11 +135,17 @@ class Repository
$this->logger = $options['logger'];
$this->initDir($dir, $options['working_dir']);
$this->objects = array();
$this->debug = (bool) $options['debug'];
$this->environmentVariables = $options['environment_variables'];
$this->processTimeout = $options['process_timeout'];
$this->objects = [];
$this->command = $options['command'];
$this->debug = (bool) $options['debug'];
$this->processTimeout = $options['process_timeout'];
if (defined('PHP_WINDOWS_VERSION_BUILD') && isset($_SERVER['PATH']) && !isset($options['environment_variables']['PATH'])) {
$options['environment_variables']['PATH'] = $_SERVER['PATH'];
}
$this->environmentVariables = $options['environment_variables'];
$this->inheritEnvironmentVariables = $options['inherit_environment_variables'];
if (true === $this->debug && null !== $this->logger) {
$this->logger->debug(sprintf('Repository created (git dir: "%s", working dir: "%s")', $this->gitDir, $this->workingDir ?: 'none'));
@@ -153,7 +164,7 @@ class Repository
if (false === $realGitDir) {
throw new InvalidArgumentException(sprintf('Directory "%s" does not exist or is not a directory', $gitDir));
} else if (!is_dir($realGitDir)) {
} elseif (!is_dir($realGitDir)) {
throw new InvalidArgumentException(sprintf('Directory "%s" does not exist or is not a directory', $realGitDir));
} elseif (null === $workingDir && is_dir($realGitDir.'/.git')) {
$workingDir = $realGitDir;
@@ -304,11 +315,13 @@ class Repository
/**
* Returns the reference list associated to the repository.
*
* @param bool $reload Reload references from the filesystem
*
* @return ReferenceBag
*/
public function getReferences()
public function getReferences($reload = false)
{
if (null === $this->referenceBag) {
if (null === $this->referenceBag || $reload) {
$this->referenceBag = new ReferenceBag($this);
}
@@ -363,6 +376,9 @@ class Repository
return $this->objects[$hash];
}
/**
* @return Blame
*/
public function getBlame($revision, $file, $lineRange = null)
{
if (is_string($revision)) {
@@ -400,7 +416,7 @@ class Repository
$revisions = new RevisionList($this, $revisions);
}
$args = array_merge(array('-r', '-p', '-m', '-M', '--no-commit-id', '--full-index'), $revisions->getAsTextArray());
$args = array_merge(['-r', '-p', '-m', '-M', '--no-commit-id', '--full-index'], $revisions->getAsTextArray());
$diff = Diff::parse($this->run('diff', $args));
$diff->setRepository($this);
@@ -412,31 +428,18 @@ class Repository
* Returns the size of repository, in kilobytes.
*
* @return int A sum, in kilobytes
*
* @throws RuntimeException An error occurred while computing size
*/
public function getSize()
{
$commandlineArguments = array('du', '-skc', $this->gitDir);
$commandline = $this->normalizeCommandlineArguments($commandlineArguments);
$process = new Process($commandline);
$process->run();
if (!preg_match('/(\d+)\s+total$/', trim($process->getOutput()), $vars)) {
$message = sprintf("Unable to parse process output\ncommand: %s\noutput: %s", $process->getCommandLine(), $process->getOutput());
if (null !== $this->logger) {
$this->logger->error($message);
$totalBytes = 0;
$path = realpath($this->gitDir);
if ($path && file_exists($path)) {
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS)) as $object) {
$totalBytes += $object->getSize();
}
if (true === $this->debug) {
throw new RuntimeException('unable to parse repository size output');
}
return;
}
return $vars[1];
return (int) ($totalBytes / 1000 + 0.5);
}
/**
@@ -444,7 +447,7 @@ class Repository
*
* @param string $command The command to execute
*/
public function shell($command, array $env = array())
public function shell($command, array $env = [])
{
$argument = sprintf('%s \'%s\'', $command, $this->gitDir);
@@ -453,7 +456,7 @@ class Repository
$prefix .= sprintf('export %s=%s;', escapeshellarg($name), escapeshellarg($value));
}
proc_open($prefix.'git shell -c '.escapeshellarg($argument), array(STDIN, STDOUT, STDERR), $pipes);
proc_open($prefix.'git shell -c '.escapeshellarg($argument), [STDIN, STDOUT, STDERR], $pipes);
}
/**
@@ -525,11 +528,11 @@ class Repository
* @param string $command Git command to run (checkout, branch, tag)
* @param array $args Arguments of git command
*
* @return string Output of a successful process or null if execution failed and debug-mode is disabled.
*
* @throws RuntimeException Error while executing git command (debug-mode only)
*
* @return string Output of a successful process or null if execution failed and debug-mode is disabled.
*/
public function run($command, $args = array())
public function run($command, $args = [])
{
$process = $this->getProcess($command, $args);
@@ -598,7 +601,7 @@ class Repository
*
* @return Repository the newly created repository
*/
public function cloneTo($path, $bare = true, array $options = array())
public function cloneTo($path, $bare = true, array $options = [])
{
return Admin::cloneTo($path, $this->gitDir, $bare, $options);
}
@@ -611,57 +614,27 @@ class Repository
*
* @see self::run
*/
private function getProcess($command, $args = array())
private function getProcess($command, $args = [])
{
$base = array($this->command, '--git-dir', $this->gitDir);
$base = [$this->command, '--git-dir', $this->gitDir];
if ($this->workingDir) {
$base = array_merge($base, array('--work-tree', $this->workingDir));
$base = array_merge($base, ['--work-tree', $this->workingDir]);
}
$base[] = $command;
$commandlineArguments = array_merge($base, $args);
$commandline = $this->normalizeCommandlineArguments($commandlineArguments);
$process = new Process(array_merge($base, $args));
if ($this->inheritEnvironmentVariables) {
$process->setEnv(array_replace($_SERVER, $this->environmentVariables));
} else {
$process->setEnv($this->environmentVariables);
}
$process = new Process($commandline);
$process->setEnv($this->environmentVariables);
$process->setTimeout($this->processTimeout);
$process->setIdleTimeout($this->processTimeout);
return $process;
}
/**
* This internal helper method is used to convert an array of commandline
* arguments to an escaped commandline string for older versions of the
* Symfony Process component.
*
* It acts as a backward compatible layer for Symfony Process < 3.3.
*
* @param array $arguments a list of command line arguments
*
* @return string|array a single escaped string (< 4.0) or a raw array of
* the arguments passed in (4.0+)
*
* @see Process::escapeArgument()
* @see ProcessUtils::escapeArgument()
*/
private function normalizeCommandlineArguments(array $arguments)
{
// From version 4.0 and onwards, the Process accepts an array of
// arguments, and escaping is taken care of automatically.
if (!class_exists('Symfony\Component\Process\ProcessBuilder')) {
return $arguments;
}
// For version < 3.3, the Process only accepts a simple string
// as commandline, and escaping has to happen manually.
$commandline = implode(' ', array_map(
'Symfony\Component\Process\ProcessUtils::escapeArgument',
$arguments
));
return $commandline;
}
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
/**

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
/**
@@ -26,9 +27,9 @@ class RevisionList implements \IteratorAggregate, \Countable
public function __construct(Repository $repository, $revisions)
{
if (is_string($revisions)) {
$revisions = array($repository->getRevision($revisions));
$revisions = [$repository->getRevision($revisions)];
} elseif ($revisions instanceof Revision) {
$revisions = array($revisions);
$revisions = [$revisions];
} elseif (!is_array($revisions)) {
throw new \InvalidArgumentException(sprintf('Expected a string, a Revision or an array, got a "%s".', is_object($revisions) ? get_class($revisions) : gettype($revisions)));
}
@@ -48,16 +49,21 @@ class RevisionList implements \IteratorAggregate, \Countable
$this->revisions = $revisions;
}
/**
* @return Revision[]
*/
public function getAll()
{
return $this->revisions;
}
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->revisions);
}
#[\ReturnTypeWillChange]
public function count()
{
return count($this->revisions);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Exception\InvalidArgumentException;
@@ -41,20 +42,20 @@ class Tree
return;
}
$output = $this->repository->run('cat-file', array('-p', $this->hash));
$output = $this->repository->run('cat-file', ['-p', $this->hash]);
$parser = new Parser\TreeParser();
$parser->parse($output);
$this->entries = array();
$this->entries = [];
foreach ($parser->entries as $entry) {
list($mode, $type, $hash, $name) = $entry;
if ($type == 'blob') {
$this->entries[$name] = array($mode, $this->repository->getBlob($hash));
$this->entries[$name] = [$mode, $this->repository->getBlob($hash)];
} elseif ($type == 'tree') {
$this->entries[$name] = array($mode, $this->repository->getTree($hash));
$this->entries[$name] = [$mode, $this->repository->getTree($hash)];
} else {
$this->entries[$name] = array($mode, new CommitReference($hash));
$this->entries[$name] = [$mode, new CommitReference($hash)];
}
}
@@ -95,7 +96,7 @@ class Tree
foreach ($segments as $segment) {
if ($element instanceof self) {
$element = $element->getEntry($segment);
} elseif ($entry instanceof Blob) {
} elseif ($element instanceof Blob) {
throw new InvalidArgumentException('Unresolvable path');
} else {
throw new UnexpectedValueException('Unknow type of element');

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Util;
/**

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git;
use Gitonomy\Git\Diff\Diff;
@@ -34,23 +35,22 @@ class WorkingCopy
}
}
public function getStatus()
{
return WorkingStatus::parseOutput();
}
public function getUntrackedFiles()
{
$lines = explode("\0", $this->run('status', array('--porcelain', '--untracked-files=all', '-z')));
$lines = array_filter($lines, function ($l) { return substr($l, 0, 3) === '?? '; });
$lines = array_map(function ($l) { return substr($l, 3); }, $lines);
$lines = explode("\0", $this->run('status', ['--porcelain', '--untracked-files=all', '-z']));
$lines = array_filter($lines, function ($l) {
return substr($l, 0, 3) === '?? ';
});
$lines = array_map(function ($l) {
return substr($l, 3);
}, $lines);
return $lines;
}
public function getDiffPending()
{
$diff = Diff::parse($this->run('diff', array('-r', '-p', '-m', '-M', '--full-index')));
$diff = Diff::parse($this->run('diff', ['-r', '-p', '-m', '-M', '--full-index']));
$diff->setRepository($this->repository);
return $diff;
@@ -58,7 +58,7 @@ class WorkingCopy
public function getDiffStaged()
{
$diff = Diff::parse($this->run('diff', array('-r', '-p', '-m', '-M', '--full-index', '--staged')));
$diff = Diff::parse($this->run('diff', ['-r', '-p', '-m', '-M', '--full-index', '--staged']));
$diff->setRepository($this->repository);
return $diff;
@@ -69,7 +69,7 @@ class WorkingCopy
*/
public function checkout($revision, $branch = null)
{
$args = array();
$args = [];
if ($revision instanceof Commit) {
$args[] = $revision->getHash();
} elseif ($revision instanceof Reference) {
@@ -81,7 +81,7 @@ class WorkingCopy
}
if (null !== $branch) {
$args = array_merge($args, array('-b', $branch));
$args = array_merge($args, ['-b', $branch]);
}
$this->run('checkout', $args);
@@ -89,7 +89,7 @@ class WorkingCopy
return $this;
}
protected function run($command, array $args = array())
protected function run($command, array $args = [])
{
return $this->repository->run($command, $args);
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Admin;
@@ -17,8 +18,9 @@ use PHPUnit\Framework\TestCase;
abstract class AbstractTest extends TestCase
{
const REPOSITORY_URL = 'http://github.com/gitonomy/foobar.git';
const REPOSITORY_URL = 'https://github.com/gitonomy/foobar.git';
const NO_MESSAGE_COMMIT = '011cd0c1625190d2959ee9a8f9f822006d94b661';
const LONGFILE_COMMIT = '4f17752acc9b7c54ba679291bf24cb7d354f0f4f';
const BEFORE_LONGFILE_COMMIT = 'e0ec50e2af75fa35485513f60b2e658e245227e9';
const LONGMESSAGE_COMMIT = '3febd664b6886344a9b32d70657687ea4b1b4fab';
@@ -51,10 +53,10 @@ abstract class AbstractTest extends TestCase
*/
public static function provideFoobar()
{
return array(
array(self::createFoobarRepository()),
array(self::createFoobarRepository(false)),
);
return [
[self::createFoobarRepository()],
[self::createFoobarRepository(false)],
];
}
/**
@@ -62,10 +64,10 @@ abstract class AbstractTest extends TestCase
*/
public static function provideEmpty()
{
return array(
array(self::createEmptyRepository()),
array(self::createEmptyRepository(false)),
);
return [
[self::createEmptyRepository()],
[self::createEmptyRepository(false)],
];
}
/**
@@ -93,7 +95,7 @@ abstract class AbstractTest extends TestCase
} else {
$dir = $repository->getGitDir();
}
AbstractTest::deleteDir($dir);
self::deleteDir($dir);
});
}
@@ -116,7 +118,7 @@ abstract class AbstractTest extends TestCase
*
* @param string $dir directory to delete
*/
public static function deleteDir($dir)
protected static function deleteDir($dir)
{
$iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
@@ -138,12 +140,12 @@ abstract class AbstractTest extends TestCase
protected static function getOptions()
{
$command = isset($_SERVER['GIT_COMMAND']) ? $_SERVER['GIT_COMMAND'] : 'git';
$envs = isset($_SERVER['GIT_ENVS']) ? (array) $_SERVER['GIT_ENVS'] : array();
$envs = isset($_SERVER['GIT_ENVS']) ? (array) $_SERVER['GIT_ENVS'] : [];
return array(
'command' => $command,
return [
'command' => $command,
'environment_variables' => $envs,
'process_timeout' => 60,
);
'process_timeout' => 60,
];
}
}

View File

@@ -9,9 +9,11 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Admin;
use Gitonomy\Git\Exception\RuntimeException;
use Gitonomy\Git\Reference\Branch;
use Gitonomy\Git\Repository;
@@ -19,14 +21,20 @@ class AdminTest extends AbstractTest
{
private $tmpDir;
public function setUp()
/**
* @before
*/
public function setUpTmpDir()
{
$this->tmpDir = self::createTempDir();
}
public function tearDown()
/**
* @after
*/
public function tearDownTmpDir()
{
$this->deleteDir(self::createTempDir());
self::deleteDir(self::createTempDir());
}
public function testBare()
@@ -36,8 +44,8 @@ class AdminTest extends AbstractTest
$objectDir = $this->tmpDir.'/objects';
$this->assertTrue($repository->isBare(), 'Repository is bare');
$this->assertTrue(is_dir($objectDir), 'objects/ folder is present');
$this->assertTrue($repository instanceof Repository, 'Admin::init returns a repository');
$this->assertDirectoryExists($objectDir, 'objects/ folder is present');
$this->assertInstanceOf(Repository::class, $repository, 'Admin::init returns a repository');
$this->assertEquals($this->tmpDir, $repository->getGitDir(), 'The folder passed as argument is git dir');
$this->assertNull($repository->getWorkingDir(), 'No working dir in bare repository');
}
@@ -49,8 +57,8 @@ class AdminTest extends AbstractTest
$objectDir = $this->tmpDir.'/.git/objects';
$this->assertFalse($repository->isBare(), 'Repository is not bare');
$this->assertTrue(is_dir($objectDir), 'objects/ folder is present');
$this->assertTrue($repository instanceof Repository, 'Admin::init returns a repository');
$this->assertDirectoryExists($objectDir, 'objects/ folder is present');
$this->assertInstanceOf(Repository::class, $repository, 'Admin::init returns a repository');
$this->assertEquals($this->tmpDir.'/.git', $repository->getGitDir(), 'git dir as subfolder of argument');
$this->assertEquals($this->tmpDir, $repository->getWorkingDir(), 'working dir present in bare repository');
}
@@ -66,12 +74,12 @@ class AdminTest extends AbstractTest
$newRefs = array_keys($new->getReferences()->getAll());
$this->assertTrue(in_array('refs/heads/master', $newRefs));
$this->assertTrue(in_array('refs/tags/0.1', $newRefs));
$this->assertContains('refs/heads/master', $newRefs);
$this->assertContains('refs/tags/0.1', $newRefs);
if ($repository->isBare()) {
$this->assertEquals($newDir, $new->getGitDir());
$this->assertTrue(in_array('refs/heads/new-feature', $newRefs));
$this->assertContains('refs/heads/new-feature', $newRefs);
} else {
$this->assertEquals($newDir.'/.git', $new->getGitDir());
$this->assertEquals($newDir, $new->getWorkingDir());
@@ -89,7 +97,7 @@ class AdminTest extends AbstractTest
self::registerDeletion($new);
$head = $new->getHead();
$this->assertTrue($head instanceof Branch, 'HEAD is a branch');
$this->assertInstanceOf(Branch::class, $head, 'HEAD is a branch');
$this->assertEquals('new-feature', $head->getName(), 'HEAD is branch new-feature');
}
@@ -104,7 +112,7 @@ class AdminTest extends AbstractTest
self::registerDeletion($new);
$head = $new->getHead();
$this->assertTrue($head instanceof Branch, 'HEAD is a branch');
$this->assertInstanceOf(Branch::class, $head, 'HEAD is a branch');
$this->assertEquals('new-feature', $head->getName(), 'HEAD is branch new-feature');
}
@@ -119,14 +127,14 @@ class AdminTest extends AbstractTest
$newRefs = array_keys($new->getReferences()->getAll());
$this->assertTrue(in_array('refs/heads/master', $newRefs));
$this->assertTrue(in_array('refs/tags/0.1', $newRefs));
$this->assertContains('refs/heads/master', $newRefs);
$this->assertContains('refs/tags/0.1', $newRefs);
$this->assertEquals($newDir, $new->getGitDir());
if ($repository->isBare()) {
$this->assertTrue(in_array('refs/heads/new-feature', $newRefs));
$this->assertContains('refs/heads/new-feature', $newRefs);
} else {
$this->assertTrue(in_array('refs/remotes/origin/new-feature', $newRefs));
$this->assertContains('refs/remotes/origin/new-feature', $newRefs);
}
}
@@ -147,11 +155,10 @@ class AdminTest extends AbstractTest
$this->assertFalse(Admin::isValidRepository($url));
}
/**
* @expectedException RuntimeException
*/
public function testExistingFile()
{
$this->expectException(RuntimeException::class);
$file = $this->tmpDir.'/test';
touch($file);
@@ -161,15 +168,15 @@ class AdminTest extends AbstractTest
public function testCloneRepository()
{
$newDir = self::createTempDir();
$args = array();
$args = [];
$new = Admin::cloneRepository($newDir, self::REPOSITORY_URL, $args, self::getOptions());
self::registerDeletion($new);
$newRefs = array_keys($new->getReferences()->getAll());
$this->assertTrue(in_array('refs/heads/master', $newRefs));
$this->assertTrue(in_array('refs/tags/0.1', $newRefs));
$this->assertContains('refs/heads/master', $newRefs);
$this->assertContains('refs/tags/0.1', $newRefs);
$this->assertEquals($newDir.'/.git', $new->getGitDir());
$this->assertEquals($newDir, $new->getWorkingDir());

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
class BlameTest extends AbstractTest

View File

@@ -9,8 +9,11 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Exception\RuntimeException;
class BlobTest extends AbstractTest
{
const README_FRAGMENT = 'Foo Bar project';
@@ -27,15 +30,20 @@ class BlobTest extends AbstractTest
{
$blob = $this->getReadmeBlob($repository);
$this->assertContains(self::README_FRAGMENT, $blob->getContent());
if (method_exists($this, 'assertStringContainsString')) {
$this->assertStringContainsString(self::README_FRAGMENT, $blob->getContent());
} else {
$this->assertContains(self::README_FRAGMENT, $blob->getContent());
}
}
/**
* @dataProvider provideFoobar
* @expectedException RuntimeException
*/
public function testNotExisting($repository)
{
$this->expectException(RuntimeException::class);
$blob = $repository->getBlob('foobar');
$blob->getContent();
}
@@ -46,7 +54,12 @@ class BlobTest extends AbstractTest
public function testGetMimetype($repository)
{
$blob = $this->getReadmeBlob($repository);
$this->assertRegexp('#text/plain#', $blob->getMimetype());
if (method_exists($this, 'assertMatchesRegularExpression')) {
$this->assertMatchesRegularExpression('#text/plain#', $blob->getMimetype());
} else {
$this->assertRegExp('#text/plain#', $blob->getMimetype());
}
}
/**

View File

@@ -9,10 +9,15 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Commit;
use Gitonomy\Git\Diff\Diff;
use Gitonomy\Git\Exception\InvalidArgumentException;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
use Gitonomy\Git\Repository;
use Gitonomy\Git\Tree;
class CommitTest extends AbstractTest
{
@@ -25,7 +30,7 @@ class CommitTest extends AbstractTest
$diff = $commit->getDiff();
$this->assertTrue($diff instanceof Diff, 'getDiff() returns a Diff object');
$this->assertInstanceOf(Diff::class, $diff, 'getDiff() returns a Diff object');
}
/**
@@ -40,13 +45,13 @@ class CommitTest extends AbstractTest
/**
* @dataProvider provideFoobar
*
* @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException
* @expectedExceptionMessage Reference not found: "that-hash-doest-not-exists"
*/
public function testInvalideHashThrowException($repository)
{
$commit = new Commit($repository, 'that-hash-doest-not-exists');
$this->expectException(ReferenceNotFoundException::class);
$this->expectExceptionMessage('Reference not found: "that-hash-doest-not-exists"');
new Commit($repository, 'that-hash-doest-not-exists');
}
/**
@@ -66,7 +71,7 @@ class CommitTest extends AbstractTest
{
$commit = $repository->getCommit(self::INITIAL_COMMIT);
$this->assertEquals(0, count($commit->getParentHashes()), 'No parent on initial commit');
$this->assertCount(0, $commit->getParentHashes(), 'No parent on initial commit');
}
/**
@@ -77,7 +82,7 @@ class CommitTest extends AbstractTest
$commit = $repository->getCommit(self::LONGFILE_COMMIT);
$parents = $commit->getParentHashes();
$this->assertEquals(1, count($parents), 'One parent found');
$this->assertCount(1, $parents, 'One parent found');
$this->assertEquals(self::BEFORE_LONGFILE_COMMIT, $parents[0], 'Parent hash is correct');
}
@@ -89,8 +94,8 @@ class CommitTest extends AbstractTest
$commit = $repository->getCommit(self::LONGFILE_COMMIT);
$parents = $commit->getParents();
$this->assertEquals(1, count($parents), 'One parent found');
$this->assertTrue($parents[0] instanceof Commit, 'First parent is a Commit object');
$this->assertCount(1, $parents, 'One parent found');
$this->assertInstanceOf(Commit::class, $parents[0], 'First parent is a Commit object');
$this->assertEquals(self::BEFORE_LONGFILE_COMMIT, $parents[0]->getHash(), "First parents's hash is correct");
}
@@ -111,7 +116,7 @@ class CommitTest extends AbstractTest
{
$commit = $repository->getCommit(self::LONGFILE_COMMIT);
$this->assertInstanceOf('Gitonomy\Git\Tree', $commit->getTree(), 'Tree is a tree');
$this->assertInstanceOf(Tree::class, $commit->getTree(), 'Tree is a tree');
$this->assertEquals('b06890c7b10904979d2f69613c2ccda30aafe262', $commit->getTree()->getHash(), 'Tree hash is correct');
}
@@ -185,6 +190,31 @@ class CommitTest extends AbstractTest
$this->assertEquals('add a long file'."\n", $commit->getMessage());
}
/**
* @dataProvider provideFoobar
*
* @param $repository Repository
*/
public function testGetEmptyMessage($repository)
{
$commit = $repository->getCommit(self::NO_MESSAGE_COMMIT);
$this->assertEquals('', $commit->getMessage());
}
/**
* @dataProvider provideFoobar
*
* @param $repository Repository
*/
public function testGetEmptyMessageFromLog($repository)
{
$commit = $repository->getCommit(self::NO_MESSAGE_COMMIT);
$commitMessageFromLog = $commit->getLog()->getCommits()[0]->getMessage();
$this->assertEquals('', $commitMessageFromLog);
}
/**
* This test ensures that GPG signed commits does not break the reading of a commit
* message.
@@ -223,14 +253,8 @@ class CommitTest extends AbstractTest
public function testGetBodyMessage($repository)
{
$commit = $repository->getCommit(self::LONGMESSAGE_COMMIT);
$message = <<<EOL
If you want to know everything,
I ran something like `chmox +x test.sh`
Hello and good bye.
EOL;
$nl = chr(10);
$message = "If you want to know everything,{$nl}I ran something like `chmox +x test.sh`{$nl}{$nl}Hello and good bye.{$nl}";
$this->assertEquals($message, $commit->getBodyMessage());
$commit = $repository->getCommit(self::INITIAL_COMMIT);
@@ -239,11 +263,12 @@ EOL;
}
/**
* @expectedException InvalidArgumentException
* @dataProvider provideFoobar
*/
public function testGetIncludingBranchesException($repository)
{
$this->expectException(InvalidArgumentException::class);
$commit = $repository->getCommit(self::INITIAL_COMMIT);
$commit->getIncludingBranches(false, false);

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Diff\Diff;
@@ -19,6 +20,7 @@ class DiffTest extends AbstractTest
const CREATE_COMMIT = 'e6fa3c792facc06faa049a6938c84c411954deb5';
const RENAME_COMMIT = '6640e0ef31518054847a1876328e26ee64083e0a';
const CHANGEMODE_COMMIT = '93da965f58170f13017477b9a608657e87e23230';
const FILE_WITH_UMLAUTS_COMMIT = '8defb9217692dc1f4c18e05e343ca91cf5047702';
/**
* @dataProvider provideFoobar
@@ -44,17 +46,17 @@ class DiffTest extends AbstractTest
{
$files = $diff->getFiles();
$this->assertEquals(2, count($files), '1 file in diff');
$this->assertCount(2, $files, '1 file in diff');
$this->assertTrue($files[0]->isCreation(), 'script_A.php created');
$this->assertEquals(null, $files[0]->getOldName(), 'First file name is a new file');
$this->assertEquals(null, $files[0]->getOldName(), 'First file name is a new file');
$this->assertEquals('script_A.php', $files[0]->getNewName(), 'First file name is script_A.php');
$this->assertEquals(null, $files[0]->getOldMode(), 'First file mode is a new file');
$this->assertEquals('100644', $files[0]->getNewMode(), 'First file mode is correct');
$this->assertEquals(null, $files[0]->getOldMode(), 'First file mode is a new file');
$this->assertEquals('100644', $files[0]->getNewMode(), 'First file mode is correct');
$this->assertEquals(1, $files[0]->getAdditions(), '1 line added');
$this->assertEquals(0, $files[0]->getDeletions(), '0 lines deleted');
$this->assertEquals(0, $files[0]->getDeletions(), '0 lines deleted');
}
/**
@@ -64,14 +66,14 @@ class DiffTest extends AbstractTest
{
$files = $repository->getCommit(self::BEFORE_LONGFILE_COMMIT)->getDiff()->getFiles();
$this->assertEquals(1, count($files), '1 files in diff');
$this->assertCount(1, $files, '1 files in diff');
$this->assertTrue($files[0]->isModification(), 'image.jpg modified');
$this->assertEquals('image.jpg', $files[0]->getOldName(), 'Second file name is image.jpg');
$this->assertEquals('image.jpg', $files[0]->getNewName(), 'Second file name is image.jpg');
$this->assertEquals('100644', $files[0]->getOldMode(), 'Second file mode is a new file');
$this->assertEquals('100644', $files[0]->getNewMode(), 'Second file mode is correct');
$this->assertEquals('100644', $files[0]->getOldMode(), 'Second file mode is a new file');
$this->assertEquals('100644', $files[0]->getNewMode(), 'Second file mode is correct');
$this->assertTrue($files[0]->isBinary(), 'binary file');
$this->assertEquals(0, $files[0]->getAdditions(), '0 lines added');
@@ -85,7 +87,7 @@ class DiffTest extends AbstractTest
{
$files = $repository->getCommit(self::DELETE_COMMIT)->getDiff()->getFiles();
$this->assertEquals(1, count($files), '1 files modified');
$this->assertCount(1, $files, '1 files modified');
$this->assertTrue($files[0]->isDeletion(), 'File deletion');
$this->assertEquals('script_B.php', $files[0]->getOldName(), 'verify old filename');
@@ -99,7 +101,7 @@ class DiffTest extends AbstractTest
{
$files = $repository->getCommit(self::RENAME_COMMIT)->getDiff()->getFiles();
$this->assertEquals(1, count($files), '1 files modified');
$this->assertCount(1, $files, '1 files modified');
$this->assertTrue($files[0]->isModification());
$this->assertTrue($files[0]->isRename());
@@ -115,7 +117,7 @@ class DiffTest extends AbstractTest
{
$files = $repository->getCommit(self::CHANGEMODE_COMMIT)->getDiff()->getFiles();
$this->assertEquals(1, count($files), '1 files modified');
$this->assertCount(1, $files, '1 files modified');
$this->assertTrue($files[0]->isModification());
$this->assertTrue($files[0]->isChangeMode());
@@ -133,10 +135,19 @@ class DiffTest extends AbstractTest
$changes = $files[0]->getChanges();
$this->assertEquals(0, $changes[0]->getRangeOldStart());
$this->assertEquals(0, $changes[0]->getRangeOldCount());
$this->assertSame(0, $changes[0]->getRangeOldStart());
$this->assertSame(0, $changes[0]->getRangeOldCount());
$this->assertEquals(1, $changes[0]->getRangeNewStart());
$this->assertEquals(0, $changes[0]->getRangeNewCount());
$this->assertSame(1, $changes[0]->getRangeNewStart());
$this->assertSame(0, $changes[0]->getRangeNewCount());
}
/**
* @dataProvider provideFoobar
*/
public function testWorksWithUmlauts($repository)
{
$files = $repository->getCommit(self::FILE_WITH_UMLAUTS_COMMIT)->getDiff()->getFiles();
$this->assertSame('file_with_umlauts_\303\244\303\266\303\274', $files[0]->getNewName());
}
}

View File

@@ -9,13 +9,20 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Exception\InvalidArgumentException;
use Gitonomy\Git\Exception\LogicException;
class HooksTest extends AbstractTest
{
private static $symlinkOnWindows = null;
public static function setUpBeforeClass()
/**
* @beforeClass
*/
public static function setUpWindows()
{
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
self::$symlinkOnWindows = true;
@@ -48,7 +55,8 @@ class HooksTest extends AbstractTest
$file = $this->hookPath($repository, $hook);
$this->assertTrue($repository->getHooks()->has($hook), "hook $hook in repository");
$this->assertTrue(file_exists($file), "Hook $hook is present");
$this->assertFileExists($file, "Hook $hook is present");
}
public function assertNoHook($repository, $hook)
@@ -56,7 +64,12 @@ class HooksTest extends AbstractTest
$file = $this->hookPath($repository, $hook);
$this->assertFalse($repository->getHooks()->has($hook), "No hook $hook in repository");
$this->assertFalse(file_exists($file), "Hook $hook is not present");
if (method_exists($this, 'assertFileDoesNotExist')) {
$this->assertFileDoesNotExist($file, "Hook $hook is not present");
} else {
$this->assertFileNotExists($file, "Hook $hook is not present");
}
}
/**
@@ -71,10 +84,11 @@ class HooksTest extends AbstractTest
/**
* @dataProvider provideFoobar
* @expectedException InvalidArgumentException
*/
public function testGet_InvalidName_ThrowsException($repository)
{
$this->expectException(InvalidArgumentException::class);
$repository->getHooks()->get('foo');
}
@@ -99,15 +113,21 @@ class HooksTest extends AbstractTest
$repository->getHooks()->setSymlink('foo', $file);
$this->assertTrue(is_link($this->hookPath($repository, 'foo')), 'foo hook is a symlink');
$this->assertEquals($file, readlink($this->hookPath($repository, 'foo')), 'target of symlink is correct');
$this->assertEquals(
str_replace('\\', '/', $file),
str_replace('\\', '/', readlink($this->hookPath($repository, 'foo'))),
'target of symlink is correct'
);
}
/**
* @dataProvider provideFoobar
* @expectedException LogicException
*/
public function testSymlink_WithExisting_ThrowsLogicException($repository)
{
$this->expectException(LogicException::class);
$this->markAsSkippedIfSymlinkIsMissing();
$file = $this->hookPath($repository, 'target-symlink');
@@ -140,7 +160,8 @@ class HooksTest extends AbstractTest
{
$repository->getHooks()->set('foo', 'bar');
$this->setExpectedException('LogicException');
$this->expectException(LogicException::class);
$repository->getHooks()->set('foo', 'bar');
}
@@ -153,15 +174,21 @@ class HooksTest extends AbstractTest
touch($file);
$repository->getHooks()->remove('foo');
$this->assertFalse(file_exists($file));
if (method_exists($this, 'assertFileDoesNotExist')) {
$this->assertFileDoesNotExist($file);
} else {
$this->assertFileNotExists($file);
}
}
/**
* @dataProvider provideFoobar
* @expectedException LogicException
*/
public function testRemove_NotExisting_ThrowsLogicException($repository)
{
$this->expectException(LogicException::class);
$repository->getHooks()->remove('foo');
}

View File

@@ -9,9 +9,8 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Log;
namespace Gitonomy\Git\Tests;
class LogTest extends AbstractTest
{
@@ -23,8 +22,8 @@ class LogTest extends AbstractTest
$logReadme = $repository->getLog(self::LONGFILE_COMMIT, 'README');
$logImage = $repository->getLog(self::LONGFILE_COMMIT, 'image.jpg');
$this->assertEquals(3, count($logReadme));
$this->assertEquals(2, count($logImage));
$this->assertCount(3, $logReadme);
$this->assertCount(2, $logImage);
}
/**
@@ -36,7 +35,7 @@ class LogTest extends AbstractTest
$commits = $log->getCommits();
$this->assertEquals(3, count($commits), '3 commits in log');
$this->assertCount(3, $commits, '3 commits in log');
$this->assertEquals(self::LONGFILE_COMMIT, $commits[0]->getHash(), 'First is requested one');
$this->assertEquals(self::BEFORE_LONGFILE_COMMIT, $commits[1]->getHash(), "Second is longfile parent\'s");
}
@@ -68,7 +67,7 @@ class LogTest extends AbstractTest
{
$log = $repository->getLog(self::LONGFILE_COMMIT);
$expectedHashes = array(self::LONGFILE_COMMIT, self::BEFORE_LONGFILE_COMMIT);
$expectedHashes = [self::LONGFILE_COMMIT, self::BEFORE_LONGFILE_COMMIT];
foreach ($log as $entry) {
$hash = array_shift($expectedHashes);
$this->assertEquals($hash, $entry->getHash());

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\PushReference;
@@ -23,12 +24,12 @@ class PushReferenceTest extends AbstractTest
public function provideIsers()
{
// mask: force fastforward create delete
return array(
array('foo', PushReference::ZERO, self::LONGFILE_COMMIT, self::CREATE),
array('foo', self::LONGFILE_COMMIT, PushReference::ZERO, self::DELETE),
array('foo', self::LONGFILE_COMMIT, self::BEFORE_LONGFILE_COMMIT, self::FORCE),
array('foo', self::BEFORE_LONGFILE_COMMIT, self::LONGFILE_COMMIT, self::FAST_FORWARD),
);
return [
['foo', PushReference::ZERO, self::LONGFILE_COMMIT, self::CREATE],
['foo', self::LONGFILE_COMMIT, PushReference::ZERO, self::DELETE],
['foo', self::LONGFILE_COMMIT, self::BEFORE_LONGFILE_COMMIT, self::FORCE],
['foo', self::BEFORE_LONGFILE_COMMIT, self::LONGFILE_COMMIT, self::FAST_FORWARD],
];
}
/**
@@ -37,10 +38,10 @@ class PushReferenceTest extends AbstractTest
public function testIsers($reference, $before, $after, $mask)
{
$reference = new PushReference(self::createFoobarRepository(), $reference, $before, $after);
$this->assertEquals($mask & self::CREATE, $reference->isCreate(), 'Create value is correct.');
$this->assertEquals($mask & self::DELETE, $reference->isDelete(), 'Delete value is correct.');
$this->assertEquals($mask & self::FORCE, $reference->isForce(), 'Force value is correct.');
$this->assertEquals($mask & self::FAST_FORWARD, $reference->isFastForward(), 'FastForward value is correct.');
$this->assertEquals($mask & self::CREATE, $reference->isCreate(), 'Create value is correct.');
$this->assertEquals($mask & self::DELETE, $reference->isDelete(), 'Delete value is correct.');
$this->assertEquals($mask & self::FORCE, $reference->isForce(), 'Force value is correct.');
$this->assertEquals($mask & self::FAST_FORWARD, $reference->isFastForward(), 'FastForward value is correct.');
}
/**
@@ -51,7 +52,7 @@ class PushReferenceTest extends AbstractTest
$ref = new PushReference($repository, 'foo', self::INITIAL_COMMIT, self::LONGFILE_COMMIT);
$log = $ref->getLog()->getCommits();
$this->assertEquals(7, count($log), '7 commits in log');
$this->assertCount(7, $log, '7 commits in log');
$this->assertEquals('add a long file', $log[0]->getShortMessage(), 'First commit is correct');
}
@@ -64,7 +65,7 @@ class PushReferenceTest extends AbstractTest
{
$ref = new PushReference($repository, 'foo', self::INITIAL_COMMIT, self::SIGNED_COMMIT);
$log = $ref->getLog()->getCommits();
$this->assertEquals(16, count($log), '16 commits in log');
$this->assertCount(16, $log, '16 commits in log');
$this->assertEquals('signed commit', $log[0]->getShortMessage(), 'Last commit is correct');
}
@@ -75,8 +76,8 @@ class PushReferenceTest extends AbstractTest
{
$ref = new PushReference($repository, 'foo', PushReference::ZERO, self::LONGFILE_COMMIT);
$log = $ref->getLog(array(self::INITIAL_COMMIT))->getCommits();
$this->assertEquals(7, count($log), '7 commits in log');
$log = $ref->getLog([self::INITIAL_COMMIT])->getCommits();
$this->assertCount(7, $log, '7 commits in log');
$this->assertEquals('add a long file', $log[0]->getShortMessage(), 'First commit is correct');
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* This file is part of Gitonomy.
*
* (c) Alexandre Salomé <alexandre.salome@gmail.com>
* (c) Julien DIDIER <genzo.wm@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Repository;
class ReferenceBagTest extends AbstractTest
{
/**
* @dataProvider provideFoobar
*/
public function testUnknownReference(Repository $repository)
{
$hash = $repository->getLog()->getSingleCommit()->getHash();
$repository->run('update-ref', ['refs/pipelines/1', $hash]);
$repository->run('update-ref', ['refs/merge-request/1/head', $hash]);
$repository->run('update-ref', ['refs/pull/1/head', $hash]);
$repository->run('update-ref', ['refs/notes/gtm-data', $hash]);
$refs = $repository->getReferences()->getAll();
if (method_exists($this, 'assertIsArray')) {
$this->assertIsArray($refs);
} else {
$this->assertInternalType('array', $refs);
}
// Check that at least it has the master ref
$this->assertArrayHasKey('refs/heads/master', $refs);
// Check that our custom refs have been ignored
$this->assertArrayNotHasKey('refs/pipelines/1', $refs);
$this->assertArrayNotHasKey('refs/merge-request/1/head', $refs);
$this->assertArrayNotHasKey('refs/pull/1/head', $refs);
$this->assertArrayNotHasKey('refs/notes/gtm-data', $refs);
}
}

View File

@@ -9,22 +9,22 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
use Gitonomy\Git\Reference\Branch;
use Gitonomy\Git\Reference\Tag;
class ReferenceTest extends AbstractTest
{
private $references;
/**
* @dataProvider provideEmpty
*/
public function testEmptyRepository($repository)
{
$this->assertCount(0, $repository->getReferences());
$this->assertEquals(array(), $repository->getReferences()->getAll());
$this->assertEquals([], $repository->getReferences()->getAll());
}
/**
@@ -34,7 +34,7 @@ class ReferenceTest extends AbstractTest
{
$branch = $repository->getReferences()->getBranch('master');
$this->assertTrue($branch instanceof Branch, 'Branch object is correct type');
$this->assertInstanceOf(Branch::class, $branch, 'Branch object is correct type');
$this->assertEquals($branch->getCommitHash(), $branch->getCommit()->getHash(), 'Hash is correctly resolved');
}
@@ -58,11 +58,12 @@ class ReferenceTest extends AbstractTest
/**
* @dataProvider provideFoobar
* @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException
*/
public function testGetBranch_NotExisting_Error($repository)
{
$branch = $repository->getReferences()->getBranch('notexisting');
$this->expectException(ReferenceNotFoundException::class);
$repository->getReferences()->getBranch('notexisting');
}
/**
@@ -72,7 +73,8 @@ class ReferenceTest extends AbstractTest
{
$tag = $repository->getReferences()->getTag('0.1');
$this->assertTrue($tag instanceof Tag, 'Tag object is correct type');
$this->assertInstanceOf(Tag::class, $tag, 'Tag object is correct type');
$this->assertFalse($tag->isAnnotated(), 'Tag is not annotated');
$this->assertEquals(self::LONGFILE_COMMIT, $tag->getCommitHash(), 'Commit hash is correct');
$this->assertEquals(self::LONGFILE_COMMIT, $tag->getCommit()->getHash(), 'Commit hash is correct');
@@ -80,11 +82,38 @@ class ReferenceTest extends AbstractTest
/**
* @dataProvider provideFoobar
* @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException
*/
public function testAnnotatedTag($repository)
{
$tag = $repository->getReferences()->getTag('annotated');
$this->assertInstanceOf(Tag::class, $tag, 'Tag object is correct type');
$this->assertTrue($tag->isAnnotated(), 'Tag is annotated');
$this->assertFalse($tag->isSigned(), 'Tag is not signed');
$this->assertEquals('Graham Campbell', $tag->getTaggerName(), 'Tagger name is correct');
$this->assertEquals('graham@alt-three.com', $tag->getTaggerEmail(), 'Tagger email is correct');
$this->assertEquals(1471428000, $tag->getTaggerDate()->getTimestamp(), 'Tag date is correct');
$this->assertEquals('heading', $tag->getSubjectMessage(), 'Message heading is correct');
$this->assertEquals("body\nbody", $tag->getBodyMessage(), 'Message body is correct');
$closure = function () {
return parent::getCommit();
};
$parentCommit = $closure->bindTo($tag, Tag::class);
$this->assertNotEquals($parentCommit()->getHash(), $tag->getCommit()->getHash(), 'Tag commit is not the same as main commit');
$this->assertEquals('fbde681b329a39e08b63dc54b341a3274c0380c0', $tag->getCommit()->getHash(), 'Tag commit is correct');
}
/**
* @dataProvider provideFoobar
*/
public function testGetTag_NotExisting_Error($repository)
{
$branch = $repository->getReferences()->getTag('notexisting');
$this->expectException(ReferenceNotFoundException::class);
$repository->getReferences()->getTag('notexisting');
}
/**
@@ -95,8 +124,8 @@ class ReferenceTest extends AbstractTest
$commit = $repository->getReferences()->getTag('0.1')->getCommit();
$resolved = $repository->getReferences()->resolve($commit->getHash());
$this->assertEquals(1, count($resolved), '1 revision resolved');
$this->assertTrue(reset($resolved) instanceof Tag, 'Resolved object is a tag');
$this->assertCount(1, $resolved, '1 revision resolved');
$this->assertInstanceOf(Tag::class, reset($resolved), 'Resolved object is a tag');
}
/**
@@ -107,8 +136,8 @@ class ReferenceTest extends AbstractTest
$commit = $repository->getReferences()->getTag('0.1')->getCommit();
$resolved = $repository->getReferences()->resolveTags($commit->getHash());
$this->assertEquals(1, count($resolved), '1 revision resolved');
$this->assertTrue(reset($resolved) instanceof Tag, 'Resolved object is a tag');
$this->assertCount(1, $resolved, '1 revision resolved');
$this->assertInstanceOf(Tag::class, reset($resolved), 'Resolved object is a tag');
}
/**
@@ -121,12 +150,12 @@ class ReferenceTest extends AbstractTest
$resolved = $repository->getReferences()->resolveBranches($master->getCommitHash());
if ($repository->isBare()) {
$this->assertEquals(1, count($resolved), '1 revision resolved');
$this->assertCount(1, $resolved, '1 revision resolved');
} else {
$this->assertEquals(2, count($resolved), '2 revision resolved');
$this->assertCount(2, $resolved, '2 revision resolved');
}
$this->assertTrue(reset($resolved) instanceof Branch, 'Resolved object is a branch');
$this->assertInstanceOf(Branch::class, reset($resolved), 'Resolved object is a branch');
}
/**
@@ -144,7 +173,7 @@ class ReferenceTest extends AbstractTest
{
$i = 0;
foreach ($repository->getReferences() as $ref) {
++$i;
$i++;
}
$this->assertGreaterThanOrEqual(2, $i, 'At least two references in repository');
}

View File

@@ -9,10 +9,11 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Blob;
use Gitonomy\Git\Repository;
use Gitonomy\Git\Exception\RuntimeException;
use Prophecy\Argument;
class RepositoryTest extends AbstractTest
@@ -20,12 +21,17 @@ class RepositoryTest extends AbstractTest
/**
* @dataProvider provideFoobar
*/
public function testGetBlob_WithExisting_Works($repository)
public function testGetBlobWithExistingWorks($repository)
{
$blob = $repository->getCommit(self::LONGFILE_COMMIT)->getTree()->resolvePath('README.md');
$this->assertTrue($blob instanceof Blob, 'getBlob() returns a Blob object');
$this->assertContains('Foo Bar project', $blob->getContent(), 'file is correct');
$this->assertInstanceOf(Blob::class, $blob, 'getBlob() returns a Blob object');
if (method_exists($this, 'assertStringContainsString')) {
$this->assertStringContainsString('Foo Bar project', $blob->getContent(), 'file is correct');
} else {
$this->assertContains('Foo Bar project', $blob->getContent(), 'file is correct');
}
}
/**
@@ -34,7 +40,8 @@ class RepositoryTest extends AbstractTest
public function testGetSize($repository)
{
$size = $repository->getSize();
$this->assertGreaterThan(70, $size, 'Repository is greater than 70KB');
$this->assertGreaterThanOrEqual(69, $size, 'Repository is at least 69KB');
$this->assertLessThan(80, $size, 'Repository is less than 80KB');
}
public function testIsBare()
@@ -66,12 +73,10 @@ class RepositoryTest extends AbstractTest
$loggerProphecy = $this->prophesize('Psr\Log\LoggerInterface');
$loggerProphecy
->info('run command: remote "" ')
->shouldBeCalledTimes(1)
;
->shouldBeCalledTimes(1);
$loggerProphecy
->debug(Argument::type('string')) // duration, return code and output
->shouldBeCalledTimes(3)
;
->shouldBeCalledTimes(3);
$repository->setLogger($loggerProphecy->reveal());
@@ -80,7 +85,6 @@ class RepositoryTest extends AbstractTest
/**
* @dataProvider provideFoobar
* @expectedException RuntimeException
*/
public function testLoggerNOk($repository)
{
@@ -88,19 +92,18 @@ class RepositoryTest extends AbstractTest
$this->markTestSkipped();
}
$this->expectException(RuntimeException::class);
$loggerProphecy = $this->prophesize('Psr\Log\LoggerInterface');
$loggerProphecy
->info(Argument::type('string'))
->shouldBeCalledTimes(1)
;
->shouldBeCalledTimes(1);
$loggerProphecy
->debug(Argument::type('string')) // duration, return code and output
->shouldBeCalledTimes(3)
;
->shouldBeCalledTimes(3);
$loggerProphecy
->error(Argument::type('string'))
->shouldBeCalledTimes(1)
;
->shouldBeCalledTimes(1);
$repository->setLogger($loggerProphecy->reveal());

View File

@@ -9,9 +9,11 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Commit;
use Gitonomy\Git\Exception\ReferenceNotFoundException;
use Gitonomy\Git\Log;
use Gitonomy\Git\Revision;
@@ -24,23 +26,24 @@ class RevisionTest extends AbstractTest
{
$revision = $repository->getRevision(self::LONGFILE_COMMIT.'^');
$this->assertTrue($revision instanceof Revision, 'Revision object type');
$this->assertInstanceOf(Revision::class, $revision, 'Revision object type');
$commit = $revision->getCommit();
$this->assertTrue($commit instanceof Commit, 'getCommit returns a Commit');
$this->assertInstanceOf(Commit::class, $commit, 'getCommit returns a Commit');
$this->assertEquals(self::BEFORE_LONGFILE_COMMIT, $commit->getHash(), 'Resolution is correct');
}
/**
* @dataProvider provideFoobar
* @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException
* @expectedExceptionMessage Can not find revision "non-existent-commit"
*/
public function testGetFailingReference($repository)
{
$revision = $repository->getRevision('non-existent-commit')->getCommit();
$this->expectException(ReferenceNotFoundException::class);
$this->expectExceptionMessage('Can not find revision "non-existent-commit"');
$repository->getRevision('non-existent-commit')->getCommit();
}
/**
@@ -52,9 +55,9 @@ class RevisionTest extends AbstractTest
$log = $revision->getLog(null, 2, 3);
$this->assertTrue($log instanceof Log, 'Log type object');
$this->assertInstanceOf(Log::class, $log, 'Log type object');
$this->assertEquals(2, $log->getOffset(), 'Log offset is passed');
$this->assertEquals(3, $log->getLimit(), 'Log limit is passed');
$this->assertEquals(array($revision), $log->getRevisions()->getAll(), 'Revision is passed');
$this->assertEquals([$revision], $log->getRevisions()->getAll(), 'Revision is passed');
}
}

View File

@@ -9,6 +9,7 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Blob;
@@ -16,6 +17,7 @@ use Gitonomy\Git\Blob;
class TreeTest extends AbstractTest
{
const PATH_RESOLVING_COMMIT = 'cc06ac171d884282202dff88c1ded499a1f89420';
/**
* @dataProvider provideFooBar
*/
@@ -25,10 +27,10 @@ class TreeTest extends AbstractTest
$entries = $tree->getEntries();
$this->assertTrue(isset($entries['long.php']), 'long.php is present');
$this->assertNotEmpty($entries['long.php'], 'long.php is present');
$this->assertTrue($entries['long.php'][1] instanceof Blob, 'long.php is a Blob');
$this->assertTrue(isset($entries['README.md']), 'README.md is present');
$this->assertNotEmpty($entries['README.md'], 'README.md is present');
$this->assertTrue($entries['README.md'][1] instanceof Blob, 'README.md is a Blob');
}
@@ -43,6 +45,6 @@ class TreeTest extends AbstractTest
$resolved = $tree->resolvePath($path);
$entries = $resolved->getEntries();
$this->assertTrue(isset($entries['d']), 'Successfully resolved source folder');
$this->assertNotEmpty($entries['d'], 'Successfully resolved source folder');
}
}

View File

@@ -9,18 +9,20 @@
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Gitonomy\Git\Tests;
use Gitonomy\Git\Admin;
use Gitonomy\Git\Exception\LogicException;
use Gitonomy\Git\Exception\RuntimeException;
use Gitonomy\Git\Reference\Branch;
class WorkingCopyTest extends AbstractTest
{
/**
* @expectedException LogicException
*/
public function testNoWorkingCopyInBare()
{
$this->expectException(LogicException::class);
$path = self::createTempDir();
$repo = Admin::init($path, true, self::getOptions());
@@ -34,7 +36,7 @@ class WorkingCopyTest extends AbstractTest
$wc->checkout('origin/new-feature', 'new-feature');
$head = $repository->getHead();
$this->assertTrue($head instanceof Branch, 'HEAD is a branch');
$this->assertInstanceOf(Branch::class, $head, 'HEAD is a branch');
$this->assertEquals('new-feature', $head->getName(), 'HEAD is branch new-feature');
}
@@ -48,7 +50,7 @@ class WorkingCopyTest extends AbstractTest
$file = $repository->getWorkingDir().'/foobar-test';
file_put_contents($file, 'test');
$repository->run('add', array($file));
$repository->run('add', [$file]);
$diffStaged = $wc->getDiffStaged();
$this->assertCount(1, $diffStaged->getFiles());
@@ -69,11 +71,10 @@ class WorkingCopyTest extends AbstractTest
$this->assertCount(1, $diffPending->getFiles());
}
/**
* @expectedException RuntimeException
*/
public function testCheckoutUnexisting()
{
$this->expectException(RuntimeException::class);
self::createFoobarRepository(false)->getWorkingCopy()->checkout('foobar');
}

View File

@@ -4,8 +4,8 @@ require __DIR__.'/../vendor/autoload.php';
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$server = array_change_key_case($_SERVER, true);
$_SERVER['GIT_ENVS'] = array();
foreach (array('PATH', 'SYSTEMROOT') as $key) {
$_SERVER['GIT_ENVS'] = [];
foreach (['PATH', 'SYSTEMROOT'] as $key) {
if (isset($server[$key])) {
$_SERVER['GIT_ENVS'][$key] = $server[$key];
}