From 9029121f05bbf8ce7661cd5331be2adec36887df Mon Sep 17 00:00:00 2001 From: "Chun-Sheng, Li" Date: Fri, 25 Oct 2019 01:10:41 +0800 Subject: [PATCH 01/61] Test enhancement (#146) --- phpunit.xml.dist | 2 +- tests/Gitonomy/Git/Tests/AdminTest.php | 34 +++++++++---------- tests/Gitonomy/Git/Tests/CommitTest.php | 15 ++++---- tests/Gitonomy/Git/Tests/DiffTest.php | 10 +++--- tests/Gitonomy/Git/Tests/HooksTest.php | 6 ++-- tests/Gitonomy/Git/Tests/LogTest.php | 6 ++-- .../Gitonomy/Git/Tests/PushReferenceTest.php | 6 ++-- tests/Gitonomy/Git/Tests/ReferenceTest.php | 24 ++++++------- tests/Gitonomy/Git/Tests/RepositoryTest.php | 2 +- tests/Gitonomy/Git/Tests/RevisionTest.php | 6 ++-- tests/Gitonomy/Git/Tests/TreeTest.php | 6 ++-- tests/Gitonomy/Git/Tests/WorkingCopyTest.php | 2 +- 12 files changed, 60 insertions(+), 59 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3696438..4d3e2b9 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,7 +14,7 @@ - tests/Gitonomy/Git/Tests + tests/Gitonomy/Git/Tests diff --git a/tests/Gitonomy/Git/Tests/AdminTest.php b/tests/Gitonomy/Git/Tests/AdminTest.php index d000dd4..cf7937f 100644 --- a/tests/Gitonomy/Git/Tests/AdminTest.php +++ b/tests/Gitonomy/Git/Tests/AdminTest.php @@ -20,12 +20,12 @@ class AdminTest extends AbstractTest { private $tmpDir; - public function setUp() + protected function setUp() { $this->tmpDir = self::createTempDir(); } - public function tearDown() + protected function tearDown() { $this->deleteDir(self::createTempDir()); } @@ -37,8 +37,8 @@ public function testBare() $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'); } @@ -50,8 +50,8 @@ public function testNotBare() $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'); } @@ -67,12 +67,12 @@ public function testClone($repository) $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()); @@ -90,7 +90,7 @@ public function testCloneBranchBare() 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'); } @@ -105,7 +105,7 @@ public function testCloneBranchNotBare() 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'); } @@ -120,14 +120,14 @@ public function testMirror($repository) $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); } } @@ -169,8 +169,8 @@ public function testCloneRepository() $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()); diff --git a/tests/Gitonomy/Git/Tests/CommitTest.php b/tests/Gitonomy/Git/Tests/CommitTest.php index d33b478..8d187c6 100644 --- a/tests/Gitonomy/Git/Tests/CommitTest.php +++ b/tests/Gitonomy/Git/Tests/CommitTest.php @@ -13,6 +13,7 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Commit; +use Gitonomy\Git\Tree; use Gitonomy\Git\Diff\Diff; class CommitTest extends AbstractTest @@ -26,7 +27,7 @@ public function testGetDiff($repository) $diff = $commit->getDiff(); - $this->assertTrue($diff instanceof Diff, 'getDiff() returns a Diff object'); + $this->assertInstanceOf(Diff::class, $diff, 'getDiff() returns a Diff object'); } /** @@ -47,7 +48,7 @@ public function testGetHash($repository) */ public function testInvalideHashThrowException($repository) { - $commit = new Commit($repository, 'that-hash-doest-not-exists'); + new Commit($repository, 'that-hash-doest-not-exists'); } /** @@ -67,7 +68,7 @@ public function testGetParentHashes_WithNoParent($repository) { $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'); } /** @@ -78,7 +79,7 @@ public function testGetParentHashes_WithOneParent($repository) $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'); } @@ -90,8 +91,8 @@ public function testGetParents_WithOneParent($repository) $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"); } @@ -112,7 +113,7 @@ public function testGetTree($repository) { $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'); } diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index d260c5e..ec0eebe 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -45,7 +45,7 @@ protected function verifyCreateCommitDiff(Diff $diff) { $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'); @@ -65,7 +65,7 @@ public function testGetFiles_Modification($repository) { $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'); @@ -86,7 +86,7 @@ public function testGetFiles_Deletion($repository) { $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'); @@ -100,7 +100,7 @@ public function testGetFiles_Rename($repository) { $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()); @@ -116,7 +116,7 @@ public function testGetFiles_Changemode($repository) { $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()); diff --git a/tests/Gitonomy/Git/Tests/HooksTest.php b/tests/Gitonomy/Git/Tests/HooksTest.php index 86cb760..f08901e 100644 --- a/tests/Gitonomy/Git/Tests/HooksTest.php +++ b/tests/Gitonomy/Git/Tests/HooksTest.php @@ -49,7 +49,7 @@ public function assertHasHook($repository, $hook) $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) @@ -57,7 +57,7 @@ public function assertNoHook($repository, $hook) $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"); + $this->assertFileNotExists($file, "Hook $hook is not present"); } /** @@ -154,7 +154,7 @@ public function testRemove($repository) touch($file); $repository->getHooks()->remove('foo'); - $this->assertFalse(file_exists($file)); + $this->assertFileNotExists($file); } /** diff --git a/tests/Gitonomy/Git/Tests/LogTest.php b/tests/Gitonomy/Git/Tests/LogTest.php index 2f123f9..cdf1563 100644 --- a/tests/Gitonomy/Git/Tests/LogTest.php +++ b/tests/Gitonomy/Git/Tests/LogTest.php @@ -22,8 +22,8 @@ public function testRevisionAndPath($repository) $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); } /** @@ -35,7 +35,7 @@ public function testGetCommits($repository) $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"); } diff --git a/tests/Gitonomy/Git/Tests/PushReferenceTest.php b/tests/Gitonomy/Git/Tests/PushReferenceTest.php index 65969d9..4490a3f 100644 --- a/tests/Gitonomy/Git/Tests/PushReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/PushReferenceTest.php @@ -52,7 +52,7 @@ public function testLog($repository) $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'); } @@ -65,7 +65,7 @@ public function testSignedLog($repository) { $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'); } @@ -77,7 +77,7 @@ public function testLogWithExclude($repository) $ref = new PushReference($repository, 'foo', PushReference::ZERO, self::LONGFILE_COMMIT); $log = $ref->getLog([self::INITIAL_COMMIT])->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'); } } diff --git a/tests/Gitonomy/Git/Tests/ReferenceTest.php b/tests/Gitonomy/Git/Tests/ReferenceTest.php index 45b626e..b1ebcfa 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceTest.php @@ -35,7 +35,7 @@ public function testGetBranch($repository) { $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'); } @@ -63,7 +63,7 @@ public function testHasTag($repository) */ public function testGetBranch_NotExisting_Error($repository) { - $branch = $repository->getReferences()->getBranch('notexisting'); + $repository->getReferences()->getBranch('notexisting'); } /** @@ -73,7 +73,7 @@ public function testGetTag($repository) { $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'); @@ -87,7 +87,7 @@ public function testAnnotatedTag($repository) { $tag = $repository->getReferences()->getTag('annotated'); - $this->assertTrue($tag instanceof Tag, 'Tag object is correct type'); + $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'); @@ -105,7 +105,7 @@ public function testAnnotatedTag($repository) */ public function testGetTag_NotExisting_Error($repository) { - $branch = $repository->getReferences()->getTag('notexisting'); + $repository->getReferences()->getTag('notexisting'); } /** @@ -116,8 +116,8 @@ public function testResolve($repository) $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'); } /** @@ -128,8 +128,8 @@ public function testResolveTags($repository) $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'); } /** @@ -142,12 +142,12 @@ public function testResolveBranches($repository) $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'); } /** diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index d00a102..d86dc84 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -24,7 +24,7 @@ public function testGetBlob_WithExisting_Works($repository) { $blob = $repository->getCommit(self::LONGFILE_COMMIT)->getTree()->resolvePath('README.md'); - $this->assertTrue($blob instanceof Blob, 'getBlob() returns a Blob object'); + $this->assertInstanceOf(Blob::class, $blob, 'getBlob() returns a Blob object'); $this->assertContains('Foo Bar project', $blob->getContent(), 'file is correct'); } diff --git a/tests/Gitonomy/Git/Tests/RevisionTest.php b/tests/Gitonomy/Git/Tests/RevisionTest.php index 2f8428d..1ffb94a 100644 --- a/tests/Gitonomy/Git/Tests/RevisionTest.php +++ b/tests/Gitonomy/Git/Tests/RevisionTest.php @@ -25,11 +25,11 @@ public function testGetCommit($repository) { $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'); } @@ -53,7 +53,7 @@ public function testGetLog($repository) $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([$revision], $log->getRevisions()->getAll(), 'Revision is passed'); diff --git a/tests/Gitonomy/Git/Tests/TreeTest.php b/tests/Gitonomy/Git/Tests/TreeTest.php index e6cbc02..4c0476d 100644 --- a/tests/Gitonomy/Git/Tests/TreeTest.php +++ b/tests/Gitonomy/Git/Tests/TreeTest.php @@ -27,10 +27,10 @@ public function testCase($repository) $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'); } @@ -45,6 +45,6 @@ public function testResolvePath($repository) $resolved = $tree->resolvePath($path); $entries = $resolved->getEntries(); - $this->assertTrue(isset($entries['d']), 'Successfully resolved source folder'); + $this->assertNotEmpty($entries['d'], 'Successfully resolved source folder'); } } diff --git a/tests/Gitonomy/Git/Tests/WorkingCopyTest.php b/tests/Gitonomy/Git/Tests/WorkingCopyTest.php index a26002f..891ac7f 100644 --- a/tests/Gitonomy/Git/Tests/WorkingCopyTest.php +++ b/tests/Gitonomy/Git/Tests/WorkingCopyTest.php @@ -35,7 +35,7 @@ public function testCheckout() $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'); } From 827384ff3b9739f06c74296c194887727016c5ee Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 24 Oct 2019 18:11:14 +0100 Subject: [PATCH 02/61] Apply fixes from StyleCI (#147) --- tests/Gitonomy/Git/Tests/CommitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Gitonomy/Git/Tests/CommitTest.php b/tests/Gitonomy/Git/Tests/CommitTest.php index 8d187c6..bd2e918 100644 --- a/tests/Gitonomy/Git/Tests/CommitTest.php +++ b/tests/Gitonomy/Git/Tests/CommitTest.php @@ -13,8 +13,8 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Commit; -use Gitonomy\Git\Tree; use Gitonomy\Git\Diff\Diff; +use Gitonomy\Git\Tree; class CommitTest extends AbstractTest { From 4b9314e1f19647b04de5f241b5924668be5e4692 Mon Sep 17 00:00:00 2001 From: "Chun-Sheng, Li" Date: Sat, 26 Oct 2019 01:38:33 +0800 Subject: [PATCH 03/61] Enhance exception tests (#148) --- tests/Gitonomy/Git/Tests/AdminTest.php | 6 +++--- tests/Gitonomy/Git/Tests/BlobTest.php | 5 ++++- tests/Gitonomy/Git/Tests/CommitTest.php | 11 +++++++---- tests/Gitonomy/Git/Tests/HooksTest.php | 14 ++++++++++---- tests/Gitonomy/Git/Tests/ReferenceTest.php | 9 +++++---- tests/Gitonomy/Git/Tests/RepositoryTest.php | 4 +++- tests/Gitonomy/Git/Tests/RevisionTest.php | 8 +++++--- tests/Gitonomy/Git/Tests/WorkingCopyTest.php | 12 ++++++------ 8 files changed, 43 insertions(+), 26 deletions(-) diff --git a/tests/Gitonomy/Git/Tests/AdminTest.php b/tests/Gitonomy/Git/Tests/AdminTest.php index cf7937f..7234bdf 100644 --- a/tests/Gitonomy/Git/Tests/AdminTest.php +++ b/tests/Gitonomy/Git/Tests/AdminTest.php @@ -13,6 +13,7 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Admin; +use Gitonomy\Git\Exception\RuntimeException; use Gitonomy\Git\Reference\Branch; use Gitonomy\Git\Repository; @@ -148,11 +149,10 @@ public function testCheckInvalidRepository() $this->assertFalse(Admin::isValidRepository($url)); } - /** - * @expectedException RuntimeException - */ public function testExistingFile() { + $this->expectException(RuntimeException::class); + $file = $this->tmpDir.'/test'; touch($file); diff --git a/tests/Gitonomy/Git/Tests/BlobTest.php b/tests/Gitonomy/Git/Tests/BlobTest.php index 8dbe271..36b1d58 100644 --- a/tests/Gitonomy/Git/Tests/BlobTest.php +++ b/tests/Gitonomy/Git/Tests/BlobTest.php @@ -12,6 +12,8 @@ namespace Gitonomy\Git\Tests; +use Gitonomy\Git\Exception\RuntimeException; + class BlobTest extends AbstractTest { const README_FRAGMENT = 'Foo Bar project'; @@ -33,10 +35,11 @@ public function testGetContent($repository) /** * @dataProvider provideFoobar - * @expectedException RuntimeException */ public function testNotExisting($repository) { + $this->expectException(RuntimeException::class); + $blob = $repository->getBlob('foobar'); $blob->getContent(); } diff --git a/tests/Gitonomy/Git/Tests/CommitTest.php b/tests/Gitonomy/Git/Tests/CommitTest.php index bd2e918..bb4b275 100644 --- a/tests/Gitonomy/Git/Tests/CommitTest.php +++ b/tests/Gitonomy/Git/Tests/CommitTest.php @@ -14,6 +14,8 @@ use Gitonomy\Git\Commit; use Gitonomy\Git\Diff\Diff; +use Gitonomy\Git\Exception\InvalidArgumentException; +use Gitonomy\Git\Exception\ReferenceNotFoundException; use Gitonomy\Git\Tree; class CommitTest extends AbstractTest @@ -42,12 +44,12 @@ public function testGetHash($repository) /** * @dataProvider provideFoobar - * - * @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException - * @expectedExceptionMessage Reference not found: "that-hash-doest-not-exists" */ public function testInvalideHashThrowException($repository) { + $this->expectException(ReferenceNotFoundException::class); + $this->expectExceptionMessage('Reference not found: "that-hash-doest-not-exists"'); + new Commit($repository, 'that-hash-doest-not-exists'); } @@ -241,11 +243,12 @@ public function testGetBodyMessage($repository) } /** - * @expectedException InvalidArgumentException * @dataProvider provideFoobar */ public function testGetIncludingBranchesException($repository) { + $this->expectException(InvalidArgumentException::class); + $commit = $repository->getCommit(self::INITIAL_COMMIT); $commit->getIncludingBranches(false, false); diff --git a/tests/Gitonomy/Git/Tests/HooksTest.php b/tests/Gitonomy/Git/Tests/HooksTest.php index f08901e..e3478c7 100644 --- a/tests/Gitonomy/Git/Tests/HooksTest.php +++ b/tests/Gitonomy/Git/Tests/HooksTest.php @@ -12,6 +12,9 @@ namespace Gitonomy\Git\Tests; +use Gitonomy\Git\Exception\InvalidArgumentException; +use Gitonomy\Git\Exception\LogicException; + class HooksTest extends AbstractTest { private static $symlinkOnWindows = null; @@ -72,10 +75,11 @@ public function testHas($repository) /** * @dataProvider provideFoobar - * @expectedException InvalidArgumentException */ public function testGet_InvalidName_ThrowsException($repository) { + $this->expectException(InvalidArgumentException::class); + $repository->getHooks()->get('foo'); } @@ -105,10 +109,11 @@ public function testSymlink($repository) /** * @dataProvider provideFoobar - * @expectedException LogicException */ public function testSymlink_WithExisting_ThrowsLogicException($repository) { + $this->expectException(LogicException::class); + $this->markAsSkippedIfSymlinkIsMissing(); $file = $this->hookPath($repository, 'target-symlink'); @@ -141,7 +146,7 @@ public function testSet_Existing_ThrowsLogicException($repository) { $repository->getHooks()->set('foo', 'bar'); - $this->expectException('LogicException'); + $this->expectException(LogicException::class); $repository->getHooks()->set('foo', 'bar'); } @@ -159,10 +164,11 @@ public function testRemove($repository) /** * @dataProvider provideFoobar - * @expectedException LogicException */ public function testRemove_NotExisting_ThrowsLogicException($repository) { + $this->expectException(LogicException::class); + $repository->getHooks()->remove('foo'); } diff --git a/tests/Gitonomy/Git/Tests/ReferenceTest.php b/tests/Gitonomy/Git/Tests/ReferenceTest.php index b1ebcfa..d1c00fc 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceTest.php @@ -12,13 +12,12 @@ 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 */ @@ -59,10 +58,11 @@ public function testHasTag($repository) /** * @dataProvider provideFoobar - * @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException */ public function testGetBranch_NotExisting_Error($repository) { + $this->expectException(ReferenceNotFoundException::class); + $repository->getReferences()->getBranch('notexisting'); } @@ -101,10 +101,11 @@ public function testAnnotatedTag($repository) /** * @dataProvider provideFoobar - * @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException */ public function testGetTag_NotExisting_Error($repository) { + $this->expectException(ReferenceNotFoundException::class); + $repository->getReferences()->getTag('notexisting'); } diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index d86dc84..6eee0e6 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -13,6 +13,7 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Blob; +use Gitonomy\Git\Exception\RuntimeException; use Prophecy\Argument; class RepositoryTest extends AbstractTest @@ -78,7 +79,6 @@ public function testLoggerOk($repository) /** * @dataProvider provideFoobar - * @expectedException RuntimeException */ public function testLoggerNOk($repository) { @@ -86,6 +86,8 @@ public function testLoggerNOk($repository) $this->markTestSkipped(); } + $this->expectException(RuntimeException::class); + $loggerProphecy = $this->prophesize('Psr\Log\LoggerInterface'); $loggerProphecy ->info(Argument::type('string')) diff --git a/tests/Gitonomy/Git/Tests/RevisionTest.php b/tests/Gitonomy/Git/Tests/RevisionTest.php index 1ffb94a..8471184 100644 --- a/tests/Gitonomy/Git/Tests/RevisionTest.php +++ b/tests/Gitonomy/Git/Tests/RevisionTest.php @@ -13,6 +13,7 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Commit; +use Gitonomy\Git\Exception\ReferenceNotFoundException; use Gitonomy\Git\Log; use Gitonomy\Git\Revision; @@ -36,12 +37,13 @@ public function testGetCommit($repository) /** * @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(); } /** diff --git a/tests/Gitonomy/Git/Tests/WorkingCopyTest.php b/tests/Gitonomy/Git/Tests/WorkingCopyTest.php index 891ac7f..dfa048f 100644 --- a/tests/Gitonomy/Git/Tests/WorkingCopyTest.php +++ b/tests/Gitonomy/Git/Tests/WorkingCopyTest.php @@ -13,15 +13,16 @@ 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()); @@ -70,11 +71,10 @@ public function testDiffPending() $this->assertCount(1, $diffPending->getFiles()); } - /** - * @expectedException RuntimeException - */ public function testCheckoutUnexisting() { + $this->expectException(RuntimeException::class); + self::createFoobarRepository(false)->getWorkingCopy()->checkout('foobar'); } From 5d154e0f944e6d0ef4fefe7777b52118057c071a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 25 Oct 2019 19:29:26 +0100 Subject: [PATCH 04/61] Allow PHPUnit 7 (#149) --- composer.json | 2 +- phpunit.xml.dist | 37 ++++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 32165d1..c528809 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "symfony/process": "^3.4|^4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7|^6.5", + "phpunit/phpunit": "^5.7|^6.5|^7.0", "psr/log": "^1.0" }, "suggest": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4d3e2b9..333343d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,21 +1,28 @@ - - - + - tests/Gitonomy/Git/Tests + ./tests/Gitonomy/Git/Tests - + + + ./src/Gitonomy/Git + + From 47c3813369c56a3438eee34b1815bd3f6493b59b Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 4 Nov 2019 15:54:42 -0700 Subject: [PATCH 05/61] Add enterprise language (#150) --- README.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 58fa583..afd88c1 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,26 @@ Anyway, it's convenient and don't need to build anything to use it. That's how w *Documentation*: http://gitonomy.com/doc/gitlib/master/ ---- - -
- - Get professional support for Git lib with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
+## Quick Start + +You can install git lib 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.1" + } +} +``` + +## 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) From 53507845cf0f2d28eb08fd717606693ce8217117 Mon Sep 17 00:00:00 2001 From: SamLast Date: Tue, 3 Dec 2019 12:48:49 +0100 Subject: [PATCH 06/61] Allow Symfony Process 5.0 (#152) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c528809..534456e 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ }, "require": { "php": "^5.6 || ^7.0", - "symfony/process": "^3.4|^4.0" + "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { "phpunit/phpunit": "^5.7|^6.5|^7.0", From 8b45eb378ea9e4bd05eea5b42f4504833635dd3c Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 3 Dec 2019 12:04:43 +0000 Subject: [PATCH 07/61] Test on PHP 7.4 and all Symfony vesions (#155) --- .travis.yml | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 39cdc5c..93aa0ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,48 @@ language: php -dist: xenial - -php: - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - 7.3 +matrix: + include: + - php: 5.6 + dist: xenial + env: SYMFONY_VERSION=^3.4 + - php: 7.0 + dist: xenial + env: SYMFONY_VERSION=^3.4 + - php: 7.1 + dist: bionic + env: SYMFONY_VERSION=^3.4 + - php: 7.1 + dist: bionic + env: SYMFONY_VERSION=^4.0 + - php: 7.2 + dist: bionic + env: SYMFONY_VERSION=^3.4 + - php: 7.2 + dist: bionic + env: SYMFONY_VERSION=^4.0 + - php: 7.2 + dist: bionic + env: SYMFONY_VERSION=^5.0 + - php: 7.3 + dist: bionic + env: SYMFONY_VERSION=^3.4 + - php: 7.3 + dist: bionic + env: SYMFONY_VERSION=^4.0 + - php: 7.3 + dist: bionic + env: SYMFONY_VERSION=^5.0 + - php: 7.4 + dist: bionic + env: SYMFONY_VERSION=^3.4 + - php: 7.4 + dist: bionic + env: SYMFONY_VERSION=^4.0 + - php: 7.4 + dist: bionic + env: SYMFONY_VERSION=^5.0 + +before_install: composer require "symfony/process:${SYMFONY_VERSION}" --no-update install: travis_retry composer install --no-interaction --no-progress --no-suggest From a0bea921266ad1c9626d712e7f8687dcc08ca528 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 8 Dec 2019 12:42:25 +0000 Subject: [PATCH 08/61] Bumped branch alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 534456e..d2d0d63 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } } } From 4849e9fcbc03012ee564f13eb66facbf839ca529 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Fri, 13 Dec 2019 05:17:18 -0500 Subject: [PATCH 09/61] Update documentation (#157) --- README.md | 32 +++++-- composer.json | 1 - doc/api/admin.md | 77 +++++++++++++++ doc/api/admin.rst | 76 --------------- doc/api/blame.md | 58 ++++++++++++ doc/api/blame.rst | 54 ----------- doc/api/{blob.rst => blob.md} | 42 ++++----- doc/api/branch.md | 16 ++++ doc/api/branch.rst | 16 ---- doc/api/commit.md | 171 ++++++++++++++++++++++++++++++++++ doc/api/commit.rst | 168 --------------------------------- doc/api/diff.md | 104 +++++++++++++++++++++ doc/api/diff.rst | 102 -------------------- doc/api/hooks.md | 80 ++++++++++++++++ doc/api/hooks.rst | 76 --------------- doc/api/log.md | 55 +++++++++++ doc/api/log.rst | 54 ----------- doc/api/references.md | 92 ++++++++++++++++++ doc/api/references.rst | 91 ------------------ doc/api/repository.md | 147 +++++++++++++++++++++++++++++ doc/api/repository.rst | 135 --------------------------- doc/api/revision.md | 28 ++++++ doc/api/revision.rst | 28 ------ doc/api/tree.md | 54 +++++++++++ doc/api/tree.rst | 54 ----------- doc/api/workingcopy.md | 47 ++++++++++ doc/api/workingcopy.rst | 45 --------- doc/debug.md | 24 +++++ doc/debug.rst | 22 ----- doc/development.md | 18 ++++ doc/development.rst | 24 ----- doc/index.md | 46 +++++++++ doc/index.rst | 59 ------------ doc/installation.md | 27 ++++++ doc/installation.rst | 20 ---- 35 files changed, 1091 insertions(+), 1052 deletions(-) create mode 100644 doc/api/admin.md delete mode 100644 doc/api/admin.rst create mode 100644 doc/api/blame.md delete mode 100644 doc/api/blame.rst rename doc/api/{blob.rst => blob.md} (51%) create mode 100644 doc/api/branch.md delete mode 100644 doc/api/branch.rst create mode 100644 doc/api/commit.md delete mode 100644 doc/api/commit.rst create mode 100644 doc/api/diff.md delete mode 100644 doc/api/diff.rst create mode 100644 doc/api/hooks.md delete mode 100644 doc/api/hooks.rst create mode 100644 doc/api/log.md delete mode 100644 doc/api/log.rst create mode 100644 doc/api/references.md delete mode 100644 doc/api/references.rst create mode 100644 doc/api/repository.md delete mode 100644 doc/api/repository.rst create mode 100644 doc/api/revision.md delete mode 100644 doc/api/revision.rst create mode 100644 doc/api/tree.md delete mode 100644 doc/api/tree.rst create mode 100644 doc/api/workingcopy.md delete mode 100644 doc/api/workingcopy.rst create mode 100644 doc/debug.md delete mode 100644 doc/debug.rst create mode 100644 doc/development.md delete mode 100644 doc/development.rst create mode 100644 doc/index.md delete mode 100644 doc/index.rst create mode 100644 doc/installation.md delete mode 100644 doc/installation.rst diff --git a/README.md b/README.md index afd88c1..4f38e20 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -Git lib for Gitonomy -==================== +Gitlib for Gitonomy +=================== [![Build Status](https://img.shields.io/travis/gitonomy/gitlib/master.svg?style=flat-square)](https://travis-ci.org/gitonomy/gitlib) [![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=master)](https://github.styleci.io/repos/5709354) -Software License +[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://opensource.org/licenses/MIT) This library provides methods to access Git repository from PHP. @@ -11,11 +11,31 @@ 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/ +## Documentation + +* [Overview](doc/index.md) +* [Debug](doc/debug.md) +* [Development](doc/development.md) +* [Installation](doc/installation.md) +* API + + [Admin](doc/api/admin.md) + + [Blame](doc/api/blame.md) + + [Blob](doc/api/blob.md) + + [Branch](doc/api/branch.md) + + [Commit](doc/api/commit.md) + + [Diff](doc/api/diff.md) + + [Hooks](doc/api/hooks.md) + + [Log](doc/api/log.md) + + [References](doc/api/references.md) + + [Repository](doc/api/repository.md) + + [Revision](doc/api/revision.md) + + [Tree](doc/api/tree.md) + + [Working Copy](doc/api/workingcopy.md) ## Quick Start -You can install git lib using [Composer](https://getcomposer.org/). Simply require the version you need: +You can install gitlib using [Composer](https://getcomposer.org/). Simply +require the version you need: ```bash $ composer require gitonomy/gitlib @@ -26,7 +46,7 @@ or edit your `composer.json` file by hand: ```json { "require": { - "gitonomy/gitlib": "^1.1" + "gitonomy/gitlib": "^1.2" } } ``` diff --git a/composer.json b/composer.json index d2d0d63..aa6c2f1 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,6 @@ "email": "alexandre.salome@gmail.com" } ], - "homepage": "http://gitonomy.com/", "autoload": { "psr-4": { "Gitonomy\\Git\\": "src/Gitonomy/Git/" diff --git a/doc/api/admin.md b/doc/api/admin.md new file mode 100644 index 0000000..ee2596e --- /dev/null +++ b/doc/api/admin.md @@ -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 + +- +- diff --git a/doc/api/admin.rst b/doc/api/admin.rst deleted file mode 100644 index f1ec8b6..0000000 --- a/doc/api/admin.rst +++ /dev/null @@ -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 diff --git a/doc/api/blame.md b/doc/api/blame.md new file mode 100644 index 0000000..78ab2ac --- /dev/null +++ b/doc/api/blame.md @@ -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()."\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: + +```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)) +) +``` diff --git a/doc/api/blame.rst b/doc/api/blame.rst deleted file mode 100644 index 7fcbdcd..0000000 --- a/doc/api/blame.rst +++ /dev/null @@ -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)) - ) diff --git a/doc/api/blob.rst b/doc/api/blob.md similarity index 51% rename from doc/api/blob.rst rename to doc/api/blob.md index 78d36c2..f5e34cc 100644 --- a/doc/api/blob.rst +++ b/doc/api/blob.md @@ -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(), "\n"; +} elseif ($blob->isBinary()) { + echo "File is binary\n"; +} +``` diff --git a/doc/api/branch.md b/doc/api/branch.md new file mode 100644 index 0000000..d6e0872 --- /dev/null +++ b/doc/api/branch.md @@ -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(); +``` diff --git a/doc/api/branch.rst b/doc/api/branch.rst deleted file mode 100644 index c7c0c40..0000000 --- a/doc/api/branch.rst +++ /dev/null @@ -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(); diff --git a/doc/api/commit.md b/doc/api/commit.md new file mode 100644 index 0000000..bd7fc58 --- /dev/null +++ b/doc/api/commit.md @@ -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()."\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: + +```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:\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 +--------------------------------------- + +```php +$branches = $commit->getIncludingBranches($includeLocalBranches, $includeRemoteBranches); +$localBranches = $commit->getIncludingBranches(true, false); +$remoteBranches = $commit->getIncludingBranches(false, true); +``` diff --git a/doc/api/commit.rst b/doc/api/commit.rst deleted file mode 100644 index d11ea81..0000000 --- a/doc/api/commit.rst +++ /dev/null @@ -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); diff --git a/doc/api/diff.md b/doc/api/diff.md new file mode 100644 index 0000000..a4878ff --- /dev/null +++ b/doc/api/diff.md @@ -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", 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: + +```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."\n"; + } elseif ($type === FileChange::LINE_ADD) { + echo '+'.$line."\n"; + } else { + echo '-'.$line."\n"; + } + } +} +``` + +To get line numbers, use the range methods: + +```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()); +``` diff --git a/doc/api/diff.rst b/doc/api/diff.rst deleted file mode 100644 index badd077..0000000 --- a/doc/api/diff.rst +++ /dev/null @@ -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()); diff --git a/doc/api/hooks.md b/doc/api/hooks.md new file mode 100644 index 0000000..eb5c8ab --- /dev/null +++ b/doc/api/hooks.md @@ -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 = <<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'); +``` diff --git a/doc/api/hooks.rst b/doc/api/hooks.rst deleted file mode 100644 index 20c4abe..0000000 --- a/doc/api/hooks.rst +++ /dev/null @@ -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 = <<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'); diff --git a/doc/api/log.md b/doc/api/log.md new file mode 100644 index 0000000..a03989a --- /dev/null +++ b/doc/api/log.md @@ -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', array('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\n", $log->countCommits()); + +// Countable interface +echo sprintf("This log contains %s commits\n", count($log)); +``` + +Offset and limit +---------------- + +Use those methods: + +```php +$log->setOffset(32); +$log->setLimit(40); + +// or read it: +$log->getOffset(); +$log->getLimit(); +``` diff --git a/doc/api/log.rst b/doc/api/log.rst deleted file mode 100644 index 5a795b9..0000000 --- a/doc/api/log.rst +++ /dev/null @@ -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(); diff --git a/doc/api/references.md b/doc/api/references.md new file mode 100644 index 0000000..c326ba3 --- /dev/null +++ b/doc/api/references.md @@ -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!"; +} +``` + +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. diff --git a/doc/api/references.rst b/doc/api/references.rst deleted file mode 100644 index 5b7fa97..0000000 --- a/doc/api/references.rst +++ /dev/null @@ -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. diff --git a/doc/api/repository.md b/doc/api/repository.md new file mode 100644 index 0000000..4aa6e51 --- /dev/null +++ b/doc/api/repository.md @@ -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', 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: + +```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\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: + +```php +$repository->setLogger(new Monolog\Logger('repository')); + +$repository->run('fetch', array('--all')); +``` + +You can also specify as an option on repository creation: + +```php +$logger = new MonologLogger('repository'); +$repository = new Repository('/path/foo', array('logger' => $logger)); +$repository->run('fetch', array('--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', array('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', array('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', array('environment_variables' => array('GIT_'))) +``` diff --git a/doc/api/repository.rst b/doc/api/repository.rst deleted file mode 100644 index 53fa07a..0000000 --- a/doc/api/repository.rst +++ /dev/null @@ -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_'))) diff --git a/doc/api/revision.md b/doc/api/revision.md new file mode 100644 index 0000000..81370c8 --- /dev/null +++ b/doc/api/revision.md @@ -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(); +``` diff --git a/doc/api/revision.rst b/doc/api/revision.rst deleted file mode 100644 index 8ffc328..0000000 --- a/doc/api/revision.rst +++ /dev/null @@ -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(); diff --git a/doc/api/tree.md b/doc/api/tree.md new file mode 100644 index 0000000..67a4014 --- /dev/null +++ b/doc/api/tree.md @@ -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."/\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: + +```php +$source = $tree->resolvePath('src/Gitonomy/Git'); + +$source instanceof Tree; +``` diff --git a/doc/api/tree.rst b/doc/api/tree.rst deleted file mode 100644 index 4641a9f..0000000 --- a/doc/api/tree.rst +++ /dev/null @@ -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; diff --git a/doc/api/workingcopy.md b/doc/api/workingcopy.md new file mode 100644 index 0000000..4ecea6c --- /dev/null +++ b/doc/api/workingcopy.md @@ -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(); +``` diff --git a/doc/api/workingcopy.rst b/doc/api/workingcopy.rst deleted file mode 100644 index 4b65223..0000000 --- a/doc/api/workingcopy.rst +++ /dev/null @@ -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(); diff --git a/doc/debug.md b/doc/debug.md new file mode 100644 index 0000000..17a8d29 --- /dev/null +++ b/doc/debug.md @@ -0,0 +1,24 @@ +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: + +```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. diff --git a/doc/debug.rst b/doc/debug.rst deleted file mode 100644 index 704fd35..0000000 --- a/doc/debug.rst +++ /dev/null @@ -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. diff --git a/doc/development.md b/doc/development.md new file mode 100644 index 0000000..d55cc8e --- /dev/null +++ b/doc/development.md @@ -0,0 +1,18 @@ +Developing gitlib +================= + +If you plan to contribute to gitlib, here are few things you should know: + +Documentation +------------- + +Documentation is now in [Markdown](https://en.wikipedia.org/wiki/Markdown) and hosted directly on Github + +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. diff --git a/doc/development.rst b/doc/development.rst deleted file mode 100644 index 986b086..0000000 --- a/doc/development.rst +++ /dev/null @@ -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. diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 0000000..b47df38 --- /dev/null +++ b/doc/index.md @@ -0,0 +1,46 @@ +# 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. + +```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')); +``` + +## Documentation +* [Debug](debug.md) +* [Development](development.md) +* [Installation](installation.md) + +## API Reference +* [Admin](api/admin.md) +* [Blame](api/blame.md) +* [Blob](api/blob.md) +* [Branch](api/branch.md) +* [Commit](api/commit.md) +* [Diff](api/diff.md) +* [Hooks](api/hooks.md) +* [Log](api/log.md) +* [References](api/references.md) +* [Repository](api/repository.md) +* [Revision](api/revision.md) +* [Tree](api/tree.md) +* [Working Copy](api/workingcopy.md) + +## 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. diff --git a/doc/index.rst b/doc/index.rst deleted file mode 100644 index 919e91c..0000000 --- a/doc/index.rst +++ /dev/null @@ -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. diff --git a/doc/installation.md b/doc/installation.md new file mode 100644 index 0000000..ae7e90d --- /dev/null +++ b/doc/installation.md @@ -0,0 +1,27 @@ +Installation of gitlib +====================== + +Autoloading +----------- + +gitlib relies on class autoloading. It does not require any additional setup. + +Using composer +-------------- + +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.2" + } +} +``` diff --git a/doc/installation.rst b/doc/installation.rst deleted file mode 100644 index 06d36d2..0000000 --- a/doc/installation.rst +++ /dev/null @@ -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" - } - } From acd7970b11740f4920d10f9c4a2ef3a6b5e44ee5 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 13 Dec 2019 13:01:43 +0000 Subject: [PATCH 10/61] Updated docs (#158) --- .github/CONTRIBUTING.md | 1 + README.md | 68 ++++++++++++++++++++++-------------- doc/{api => }/admin.md | 0 doc/{api => }/blame.md | 2 +- doc/{api => }/blob.md | 4 +-- doc/{api => }/branch.md | 0 doc/{api => }/commit.md | 10 +++--- doc/debug.md | 24 ------------- doc/development.md | 18 ---------- doc/{api => }/diff.md | 16 ++++----- doc/{api => }/hooks.md | 0 doc/index.md | 46 ------------------------ doc/installation.md | 27 -------------- doc/{api => }/log.md | 6 ++-- doc/{api => }/references.md | 2 +- doc/{api => }/repository.md | 22 ++++++------ doc/{api => }/revision.md | 0 doc/{api => }/tree.md | 4 +-- doc/{api => }/workingcopy.md | 0 19 files changed, 75 insertions(+), 175 deletions(-) rename doc/{api => }/admin.md (100%) rename doc/{api => }/blame.md (93%) rename doc/{api => }/blob.md (91%) rename doc/{api => }/branch.md (100%) rename doc/{api => }/commit.md (94%) delete mode 100644 doc/debug.md delete mode 100644 doc/development.md rename doc/{api => }/diff.md (78%) rename doc/{api => }/hooks.md (100%) delete mode 100644 doc/index.md delete mode 100644 doc/installation.md rename doc/{api => }/log.md (81%) rename doc/{api => }/references.md (98%) rename doc/{api => }/repository.md (83%) rename doc/{api => }/revision.md (100%) rename doc/{api => }/tree.md (93%) rename doc/{api => }/workingcopy.md (100%) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0f98282..7c8267d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -27,5 +27,6 @@ Then run [PHPUnit](https://phpunit.de/): $ 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 [Travis CI](https://travis-ci.org/) against pull requests. * We also have [StyleCI](https://styleci.io/) setup to automatically fix any code style issues. diff --git a/README.md b/README.md index 4f38e20..91b8a64 100644 --- a/README.md +++ b/README.md @@ -5,37 +5,16 @@ Gitlib for Gitonomy [![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=master)](https://github.styleci.io/repos/5709354) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://opensource.org/licenses/MIT) -This library provides methods to access Git repository from PHP. +This library provides methods to access Git repository from PHP 5.6 or 7. 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 - -* [Overview](doc/index.md) -* [Debug](doc/debug.md) -* [Development](doc/development.md) -* [Installation](doc/installation.md) -* API - + [Admin](doc/api/admin.md) - + [Blame](doc/api/blame.md) - + [Blob](doc/api/blob.md) - + [Branch](doc/api/branch.md) - + [Commit](doc/api/commit.md) - + [Diff](doc/api/diff.md) - + [Hooks](doc/api/hooks.md) - + [Log](doc/api/log.md) - + [References](doc/api/references.md) - + [Repository](doc/api/repository.md) - + [Revision](doc/api/revision.md) - + [Tree](doc/api/tree.md) - + [Working Copy](doc/api/workingcopy.md) - -## Quick Start - -You can install gitlib using [Composer](https://getcomposer.org/). Simply -require the version you need: +Quick Start +----------- + +You can install gitlib using [Composer](https://getcomposer.org/). Simply require the version you need: ```bash $ composer require gitonomy/gitlib @@ -51,7 +30,42 @@ or edit your `composer.json` file by hand: } ``` -## For Enterprise +Example Usage +------------- + +```php +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 diff --git a/doc/api/admin.md b/doc/admin.md similarity index 100% rename from doc/api/admin.md rename to doc/admin.md diff --git a/doc/api/blame.md b/doc/blame.md similarity index 93% rename from doc/api/blame.md rename to doc/blame.md index 78ab2ac..80816c9 100644 --- a/doc/api/blame.md +++ b/doc/blame.md @@ -11,7 +11,7 @@ $blame = $repository->getBlame('master', 'README.md'); foreach ($blame->getLines() as $lineNumber => $line) { $commit = $line->getCommit(); - echo $lineNumber.': '.$line->getContent()." - ".$commit->getAuthorName()."\n"; + echo $lineNumber.': '.$line->getContent().' - '.$commit->getAuthorName().PHP_EOL; } ``` diff --git a/doc/api/blob.md b/doc/blob.md similarity index 91% rename from doc/api/blob.md rename to doc/blob.md index f5e34cc..2ed3bd4 100644 --- a/doc/api/blob.md +++ b/doc/blob.md @@ -37,8 +37,8 @@ You can also test if *Blob* is a text of a binary file: ```php if ($blob->isText()) { - echo $blob->getContent(), "\n"; + echo $blob->getContent(), PHP_EOL; } elseif ($blob->isBinary()) { - echo "File is binary\n"; + echo 'File is binary', PHP_EOL; } ``` diff --git a/doc/api/branch.md b/doc/branch.md similarity index 100% rename from doc/api/branch.md rename to doc/branch.md diff --git a/doc/api/commit.md b/doc/commit.md similarity index 94% rename from doc/api/commit.md rename to doc/commit.md index bd7fc58..08e9b1e 100644 --- a/doc/api/commit.md +++ b/doc/commit.md @@ -31,7 +31,7 @@ For example, if you want to display all parents, starting from a commit: ```php function displayLog(Gitonomy\Git\Commit $commit) { - echo '- '.$commit->getShortMessage()."\n"; + echo '- '.$commit->getShortMessage().PHP_EOL; foreach ($commit->getParents() as $parent) { displayLog($parent); } @@ -155,10 +155,10 @@ Here is a very straightforward example: ```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(); +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 diff --git a/doc/debug.md b/doc/debug.md deleted file mode 100644 index 17a8d29..0000000 --- a/doc/debug.md +++ /dev/null @@ -1,24 +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: - -```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. diff --git a/doc/development.md b/doc/development.md deleted file mode 100644 index d55cc8e..0000000 --- a/doc/development.md +++ /dev/null @@ -1,18 +0,0 @@ -Developing gitlib -================= - -If you plan to contribute to gitlib, here are few things you should know: - -Documentation -------------- - -Documentation is now in [Markdown](https://en.wikipedia.org/wiki/Markdown) and hosted directly on Github - -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. diff --git a/doc/api/diff.md b/doc/diff.md similarity index 78% rename from doc/api/diff.md rename to doc/diff.md index a4878ff..2ce7870 100644 --- a/doc/api/diff.md +++ b/doc/diff.md @@ -32,11 +32,11 @@ represents the modifications for a single file. ```php $files = $diff->getFiles(); -echo sprintf("%s files modified", count($files)); +echo sprintf('%s files modified%s', count($files), PHP_EOL); 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()); + 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); } ``` @@ -86,11 +86,11 @@ foreach ($changes as $change) { foreach ($lines as $data) { list ($type, $line) = $data; if ($type === FileChange::LINE_CONTEXT) { - echo ' '.$line."\n"; + echo ' '.$line.PHP_EOL; } elseif ($type === FileChange::LINE_ADD) { - echo '+'.$line."\n"; + echo '+'.$line.PHP_EOL; } else { - echo '-'.$line."\n"; + echo '-'.$line.PHP_EOL; } } } @@ -99,6 +99,6 @@ foreach ($changes as $change) { To get line numbers, use the range methods: ```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()); +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); ``` diff --git a/doc/api/hooks.md b/doc/hooks.md similarity index 100% rename from doc/api/hooks.md rename to doc/hooks.md diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index b47df38..0000000 --- a/doc/index.md +++ /dev/null @@ -1,46 +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. - -```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')); -``` - -## Documentation -* [Debug](debug.md) -* [Development](development.md) -* [Installation](installation.md) - -## API Reference -* [Admin](api/admin.md) -* [Blame](api/blame.md) -* [Blob](api/blob.md) -* [Branch](api/branch.md) -* [Commit](api/commit.md) -* [Diff](api/diff.md) -* [Hooks](api/hooks.md) -* [Log](api/log.md) -* [References](api/references.md) -* [Repository](api/repository.md) -* [Revision](api/revision.md) -* [Tree](api/tree.md) -* [Working Copy](api/workingcopy.md) - -## 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. diff --git a/doc/installation.md b/doc/installation.md deleted file mode 100644 index ae7e90d..0000000 --- a/doc/installation.md +++ /dev/null @@ -1,27 +0,0 @@ -Installation of gitlib -====================== - -Autoloading ------------ - -gitlib relies on class autoloading. It does not require any additional setup. - -Using composer --------------- - -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.2" - } -} -``` diff --git a/doc/api/log.md b/doc/log.md similarity index 81% rename from doc/api/log.md rename to doc/log.md index a03989a..4dc5a46 100644 --- a/doc/api/log.md +++ b/doc/log.md @@ -24,7 +24,7 @@ $log = $repository->getLog('master'); $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); +$log = $repository->getLog('master', ['README', 'UPGRADE'], 0, 10); ``` Counting @@ -34,10 +34,10 @@ If you want to count overall commits, without offset or limit, use the *countCommits* method: ```php -echo sprintf("This log contains %s commits\n", $log->countCommits()); +echo sprintf('This log contains %s commits%s', $log->countCommits(), PHP_EOL); // Countable interface -echo sprintf("This log contains %s commits\n", count($log)); +echo sprintf('This log contains %s commits%s', count($log), PHP_EOL); ``` Offset and limit diff --git a/doc/api/references.md b/doc/references.md similarity index 98% rename from doc/api/references.md rename to doc/references.md index c326ba3..6443092 100644 --- a/doc/api/references.md +++ b/doc/references.md @@ -15,7 +15,7 @@ First, you can test existence of tags and branches like this: ```php if ($references->hasBranch('master') && $references->hasTag('0.1')) { - echo "Good start!"; + echo 'Good start!'.PHP_EOL; } ``` diff --git a/doc/api/repository.md b/doc/repository.md similarity index 83% rename from doc/api/repository.md rename to doc/repository.md index 4aa6e51..05b4a4e 100644 --- a/doc/api/repository.md +++ b/doc/repository.md @@ -28,10 +28,10 @@ Available options are: An example: ```php -$repository = new Repository('/path/to/repo', array( +$repository = new Repository('/path/to/repo', [ 'debug' => true, - 'logger' => new Monolog\Logger() -)); + 'logger' => new Monolog\Logger(), +]); ``` Test if a repository is bare @@ -59,7 +59,7 @@ The returned size is in kilobytes: ```php $size = $repository->getSize(); -echo "Your repository size is ".$size."KB"; +echo 'Your repository size is '.$size.'KB'; ``` Access HEAD @@ -74,7 +74,7 @@ $head = $repository->getHead(); // Commit or Reference $head = $repository->getHeadCommit(); // Commit if ($repository->isHeadDetached()) { - echo "Sorry man\n"; + echo 'Sorry man'.PHP_EOL; } ``` @@ -91,15 +91,15 @@ You call method `setLogger` as an option on repository creation: ```php $repository->setLogger(new Monolog\Logger('repository')); -$repository->run('fetch', array('--all')); +$repository->run('fetch', ['--all']); ``` You can also specify as an option on repository creation: ```php $logger = new MonologLogger('repository'); -$repository = new Repository('/path/foo', array('logger' => $logger)); -$repository->run('fetch', array('--all')); +$repository = new Repository('/path/foo', ['logger' => $logger]); +$repository->run('fetch', ['--all']); ``` This will output: @@ -120,7 +120,7 @@ This will make `Repository` log errors and return empty data instead of throwing exceptions. ```php -$repository = new Repository('/tmp/foo', array('debug' => false, 'logger' => $logger)); +$repository = new Repository('/tmp/foo', ['debug' => false, 'logger' => $logger]); ``` > **note** @@ -135,7 +135,7 @@ 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', array('command' => '/home/alice/bin/git')); +$repository = new Gitonomy\Git\Repository('/tmp/foo', ['command' => '/home/alice/bin/git']); ``` ### Environment variables @@ -143,5 +143,5 @@ $repository = new Gitonomy\Git\Repository('/tmp/foo', array('command' => '/home/ It is possible to send environment variables to the `git` commands. ```php -$repository = new Gitonomy\Git\Repository('/tmp/foo', array('environment_variables' => array('GIT_'))) +$repository = new Gitonomy\Git\Repository('/tmp/foo', ['environment_variables' => ['GIT_']]) ``` diff --git a/doc/api/revision.md b/doc/revision.md similarity index 100% rename from doc/api/revision.md rename to doc/revision.md diff --git a/doc/api/tree.md b/doc/tree.md similarity index 93% rename from doc/api/tree.md rename to doc/tree.md index 67a4014..0c5c8ef 100644 --- a/doc/api/tree.md +++ b/doc/tree.md @@ -26,10 +26,10 @@ function displayTree(Tree $tree, $indent = 0) foreach ($tree->getEntries() as $name => $data) { list($mode, $entry) = $data; if ($entry instanceof Tree) { - echo $indent.$name."/\n"; + echo $indent.$name.'/'.PHP_EOL; displayTree($tree, $indent + 1); } else { - echo $indent.$name."\n"; + echo $indent.$name.PHP_EOL; } } } diff --git a/doc/api/workingcopy.md b/doc/workingcopy.md similarity index 100% rename from doc/api/workingcopy.md rename to doc/workingcopy.md From b4620be3929be291438d8d9dec153f05f4ac5817 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 13 Dec 2019 13:07:53 +0000 Subject: [PATCH 11/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91b8a64..7d02e69 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ use Gitonomy\Git\Repository; $repository = new Repository('/path/to/repository'); foreach ($repository->getReferences()->getBranches() as $branch) { - echo "- ".$branch->getName().PHP_EOL; + echo '- '.$branch->getName().PHP_EOL; } $repository->run('fetch', ['--all']); From 169a1d222c4fdedc810170f6dee797e8cc398ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Casanova=20Gonz=C3=A1lez?= Date: Tue, 7 Jan 2020 10:12:07 +0100 Subject: [PATCH 12/61] Ignore unknown refs instead of throwing an exception (#161) --- src/Gitonomy/Git/ReferenceBag.php | 6 --- tests/Gitonomy/Git/Tests/ReferenceBagTest.php | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/Gitonomy/Git/Tests/ReferenceBagTest.php diff --git a/src/Gitonomy/Git/ReferenceBag.php b/src/Gitonomy/Git/ReferenceBag.php index 178fd9f..57aec25 100644 --- a/src/Gitonomy/Git/ReferenceBag.php +++ b/src/Gitonomy/Git/ReferenceBag.php @@ -366,12 +366,6 @@ protected function initialize() } 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)); } } } diff --git a/tests/Gitonomy/Git/Tests/ReferenceBagTest.php b/tests/Gitonomy/Git/Tests/ReferenceBagTest.php new file mode 100644 index 0000000..35756bf --- /dev/null +++ b/tests/Gitonomy/Git/Tests/ReferenceBagTest.php @@ -0,0 +1,47 @@ + + * (c) Julien DIDIER + * + * 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); + } +} From 4daa5a2e77d3ce48bae2695561ea5b917b0d1631 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Mar 2020 10:24:35 +0000 Subject: [PATCH 13/61] Fixed some tests on Windows (#168) Co-authored-by: Bruce Wells --- tests/Gitonomy/Git/Tests/AbstractTest.php | 2 +- tests/Gitonomy/Git/Tests/CommitTest.php | 10 ++-------- tests/Gitonomy/Git/Tests/HooksTest.php | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/Gitonomy/Git/Tests/AbstractTest.php b/tests/Gitonomy/Git/Tests/AbstractTest.php index a47f379..13f40da 100644 --- a/tests/Gitonomy/Git/Tests/AbstractTest.php +++ b/tests/Gitonomy/Git/Tests/AbstractTest.php @@ -18,7 +18,7 @@ abstract class AbstractTest extends TestCase { - const REPOSITORY_URL = 'http://github.com/gitonomy/foobar.git'; + const REPOSITORY_URL = 'https://github.com/gitonomy/foobar.git'; const LONGFILE_COMMIT = '4f17752acc9b7c54ba679291bf24cb7d354f0f4f'; const BEFORE_LONGFILE_COMMIT = 'e0ec50e2af75fa35485513f60b2e658e245227e9'; diff --git a/tests/Gitonomy/Git/Tests/CommitTest.php b/tests/Gitonomy/Git/Tests/CommitTest.php index bb4b275..8dca9c4 100644 --- a/tests/Gitonomy/Git/Tests/CommitTest.php +++ b/tests/Gitonomy/Git/Tests/CommitTest.php @@ -227,14 +227,8 @@ public function testGetShortMessage($repository) 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); diff --git a/tests/Gitonomy/Git/Tests/HooksTest.php b/tests/Gitonomy/Git/Tests/HooksTest.php index e3478c7..597a0b4 100644 --- a/tests/Gitonomy/Git/Tests/HooksTest.php +++ b/tests/Gitonomy/Git/Tests/HooksTest.php @@ -104,7 +104,7 @@ public function testSymlink($repository) $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'); } /** From 0c787ab991dca1ebd1618544d1a699bf57f7d817 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Mar 2020 10:24:44 +0000 Subject: [PATCH 14/61] Fixed Travis CI readme badge (#169) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d02e69..7aae7fc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Gitlib for Gitonomy =================== -[![Build Status](https://img.shields.io/travis/gitonomy/gitlib/master.svg?style=flat-square)](https://travis-ci.org/gitonomy/gitlib) +[![Build Status](https://img.shields.io/travis/com/gitonomy/gitlib/master.svg?style=flat-square)](https://travis-ci.com/gitonomy/gitlib) [![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=master)](https://github.styleci.io/repos/5709354) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://opensource.org/licenses/MIT) From 07ea495aa066bea125ea74b26da086d5d30627a4 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Mar 2020 10:30:17 +0000 Subject: [PATCH 15/61] Update .gitignore (#170) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index abb9c75..bc959c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/vendor /composer.lock /phpunit.xml +/vendor From 5448d79b30fe162fb4540ce61d346668f7987c0f Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Mar 2020 15:04:44 +0000 Subject: [PATCH 16/61] Get real commit for annotated tag (#171) --- src/Gitonomy/Git/Reference/Tag.php | 28 ++++++++++++++++++++++ tests/Gitonomy/Git/Tests/ReferenceTest.php | 7 ++++++ 2 files changed, 35 insertions(+) diff --git a/src/Gitonomy/Git/Reference/Tag.php b/src/Gitonomy/Git/Reference/Tag.php index e80fde0..f8461e1 100644 --- a/src/Gitonomy/Git/Reference/Tag.php +++ b/src/Gitonomy/Git/Reference/Tag.php @@ -14,6 +14,7 @@ use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\RuntimeException; +use Gitonomy\Git\Parser\ReferenceParser; use Gitonomy\Git\Parser\TagParser; use Gitonomy\Git\Reference; @@ -21,6 +22,7 @@ * Representation of a tag reference. * * @author Alexandre Salomé + * @author Bruce Wells */ class Tag extends Reference { @@ -49,6 +51,32 @@ public function isAnnotated() 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 $row) { + list($commitHash, $fullname) = $row; + } + + return $this->repository->getCommit($commitHash); + } catch (ProcessException $e) { + // ignore the exception + } + } + + return parent::getCommit(); + } + /** * Returns the tagger name. * diff --git a/tests/Gitonomy/Git/Tests/ReferenceTest.php b/tests/Gitonomy/Git/Tests/ReferenceTest.php index d1c00fc..d24a5e6 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceTest.php @@ -97,6 +97,13 @@ public function testAnnotatedTag($repository) $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'); } /** From e3b26db65f303e6421e4dbf60aa4b0c2ea2a2506 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 21 Mar 2020 11:35:57 +0000 Subject: [PATCH 17/61] Configurable inheritance of environment variables (#173) --- src/Gitonomy/Git/Repository.php | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Gitonomy/Git/Repository.php b/src/Gitonomy/Git/Repository.php index 36e3585..fc65c86 100644 --- a/src/Gitonomy/Git/Repository.php +++ b/src/Gitonomy/Git/Repository.php @@ -86,6 +86,11 @@ class Repository */ protected $environmentVariables; + /** + * @var bool + */ + protected $inheritEnvironmentVariables; + /** * Timeout that should be set for every running process. * @@ -113,14 +118,14 @@ class Repository */ public function __construct($dir, $options = []) { - $is_windows = defined('PHP_WINDOWS_VERSION_BUILD'); $options = array_merge([ - 'working_dir' => null, - 'debug' => true, - 'logger' => null, - 'environment_variables' => $is_windows ? ['PATH' => getenv('path')] : [], - 'command' => 'git', - 'process_timeout' => 3600, + '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) { @@ -131,10 +136,16 @@ public function __construct($dir, $options = []) $this->initDir($dir, $options['working_dir']); $this->objects = []; + $this->command = $options['command']; $this->debug = (bool) $options['debug']; - $this->environmentVariables = $options['environment_variables']; $this->processTimeout = $options['process_timeout']; - $this->command = $options['command']; + + 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')); @@ -620,7 +631,13 @@ private function getProcess($command, $args = []) $base[] = $command; $process = new Process(array_merge($base, $args)); - $process->setEnv($this->environmentVariables); + + if ($this->inheritEnvironmentVariables) { + $process->setEnv(array_replace($_SERVER, $this->environmentVariables)); + } else { + $process->setEnv($this->environmentVariables); + } + $process->setTimeout($this->processTimeout); $process->setIdleTimeout($this->processTimeout); From 2d18d67b45afec54311d5fad6d72c2ee94431d87 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Sat, 21 Mar 2020 07:36:55 -0400 Subject: [PATCH 18/61] Php only Repository::getsize (#174) Co-authored-by: Graham Campbell --- src/Gitonomy/Git/Repository.php | 23 ++++++--------------- tests/Gitonomy/Git/Tests/RepositoryTest.php | 3 ++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/Gitonomy/Git/Repository.php b/src/Gitonomy/Git/Repository.php index fc65c86..ae01979 100644 --- a/src/Gitonomy/Git/Repository.php +++ b/src/Gitonomy/Git/Repository.php @@ -422,30 +422,19 @@ public function getDiff($revisions) /** * Returns the size of repository, in kilobytes. * - * @throws RuntimeException An error occurred while computing size - * * @return int A sum, in kilobytes */ public function getSize() { - $process = new Process(['du', '-skc', $this->gitDir]); - $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); } /** diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index 6eee0e6..2cafdd2 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -35,7 +35,8 @@ public function testGetBlob_WithExisting_Works($repository) 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() From 0cbac31d7a0c62310feefc807cbb26297c7d2f19 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 23 Mar 2020 10:58:55 +0000 Subject: [PATCH 19/61] Added missing mbstring soft requirement (#175) --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index aa6c2f1..0e5f172 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ }, "require": { "php": "^5.6 || ^7.0", + "symfony/polyfill-mbstring": "^1.7", "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { From 718ca021c67f3ea8f6a5fa5d231ec49675068868 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 23 Mar 2020 12:43:44 +0000 Subject: [PATCH 20/61] Added remaining missing requirements (#177) --- composer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/composer.json b/composer.json index 0e5f172..805fbff 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ }, "require": { "php": "^5.6 || ^7.0", + "ext-pcre": "*", "symfony/polyfill-mbstring": "^1.7", "symfony/process": "^3.4|^4.0|^5.0" }, @@ -40,6 +41,7 @@ "psr/log": "^1.0" }, "suggest": { + "ext-fileinfo": "Required to determine the mimetype of a blob", "psr/log": "Required to use loggers for reporting of execution" }, "extra": { From f0fa7829b4d9541c16178dfcec01e4243260dbb3 Mon Sep 17 00:00:00 2001 From: Gilles Doge Date: Sat, 28 Mar 2020 17:07:20 +0100 Subject: [PATCH 21/61] [doc] Fix small typo (#178) --- doc/admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/admin.md b/doc/admin.md index ee2596e..d477680 100644 --- a/doc/admin.md +++ b/doc/admin.md @@ -43,7 +43,7 @@ non-bare repository, this branch will be checked out: $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); +$repository = Gitonomy\Git\Admin::cloneBranchTo('/tmp/gitlib', 'https://github.com/gitonomy/gitlib.git', 'a-branch', false); ``` Clone a Repository object From 5ffc63876d39531f05dfbc74d59aaae46ae7df2c Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 13 Apr 2020 12:37:29 +0100 Subject: [PATCH 22/61] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 93aa0ff..db3bdc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,8 +42,8 @@ matrix: dist: bionic env: SYMFONY_VERSION=^5.0 -before_install: composer require "symfony/process:${SYMFONY_VERSION}" --no-update +before_install: travis_retry composer require "symfony/process:${SYMFONY_VERSION}" --no-update -install: travis_retry composer install --no-interaction --no-progress --no-suggest +install: travis_retry composer install --prefer-dist --no-progress -n -o script: vendor/bin/phpunit From ce2f9b77f0739bb343d4b6b802561e02b8a6fbc4 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 13 Apr 2020 12:39:22 +0100 Subject: [PATCH 23/61] Added missing dev extension requirement --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 805fbff..6c57fc4 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,7 @@ "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { + "ext-fileinfo": "*", "phpunit/phpunit": "^5.7|^6.5|^7.0", "psr/log": "^1.0" }, From 3d70f3504ee0d3b687917312af96a22f649bcf3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1=20Pereira?= Date: Tue, 14 Apr 2020 09:47:33 +0100 Subject: [PATCH 24/61] Allow reload references from filesystem (#179) --- src/Gitonomy/Git/Repository.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Gitonomy/Git/Repository.php b/src/Gitonomy/Git/Repository.php index ae01979..3920616 100644 --- a/src/Gitonomy/Git/Repository.php +++ b/src/Gitonomy/Git/Repository.php @@ -315,11 +315,13 @@ public function getWorkingCopy() /** * 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); } From c6ba917bcf09bf56a9e839dfa9c4d7942a062751 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 30 Jul 2020 15:39:09 +0100 Subject: [PATCH 25/61] Added support for PHP 8.0 (#180) --- .gitignore | 1 + .travis.yml | 22 +++++++++++++--- composer.json | 6 ++--- phpunit.xml.dist | 2 +- tests/Gitonomy/Git/Tests/AbstractTest.php | 2 +- tests/Gitonomy/Git/Tests/AdminTest.php | 12 ++++++--- tests/Gitonomy/Git/Tests/BlobTest.php | 13 ++++++++-- tests/Gitonomy/Git/Tests/HooksTest.php | 28 ++++++++++++++++++--- tests/Gitonomy/Git/Tests/RepositoryTest.php | 9 +++++-- 9 files changed, 75 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index bc959c5..376a2cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.phpunit.result.cache /composer.lock /phpunit.xml /vendor diff --git a/.travis.yml b/.travis.yml index db3bdc7..6b17e26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,9 +41,23 @@ matrix: - php: 7.4 dist: bionic env: SYMFONY_VERSION=^5.0 + - php: nightly + dist: bionic + env: SYMFONY_VERSION=^3.4 + - php: nightly + dist: bionic + env: SYMFONY_VERSION=^4.0 + - php: nightly + dist: bionic + env: SYMFONY_VERSION=^5.0 -before_install: travis_retry composer require "symfony/process:${SYMFONY_VERSION}" --no-update - -install: travis_retry composer install --prefer-dist --no-progress -n -o +before_install: + - composer self-update --2 + - travis_retry composer require "symfony/process:${SYMFONY_VERSION}" --no-update -script: vendor/bin/phpunit +install: + - if [[ "$TRAVIS_PHP_VERSION" != 'nightly' ]]; then travis_retry composer update --prefer-dist --no-progress -n -o; fi + - if [[ "$TRAVIS_PHP_VERSION" = 'nightly' ]]; then travis_retry composer update --ignore-platform-req=php --prefer-dist --no-progress -n -o; fi + +script: + - vendor/bin/phpunit diff --git a/composer.json b/composer.json index 6c57fc4..9211620 100644 --- a/composer.json +++ b/composer.json @@ -31,14 +31,14 @@ } }, "require": { - "php": "^5.6 || ^7.0", + "php": "^5.6 || ^7.0 || ^8.0", "ext-pcre": "*", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4|^4.0|^5.0" + "symfony/process": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { "ext-fileinfo": "*", - "phpunit/phpunit": "^5.7|^6.5|^7.0", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", "psr/log": "^1.0" }, "suggest": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 333343d..fd8be6a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -9,7 +9,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" failOnRisky="true" - failOnWarning="true" + failOnWarning="false" processIsolation="false" stopOnError="false" stopOnFailure="false" diff --git a/tests/Gitonomy/Git/Tests/AbstractTest.php b/tests/Gitonomy/Git/Tests/AbstractTest.php index 13f40da..d586eda 100644 --- a/tests/Gitonomy/Git/Tests/AbstractTest.php +++ b/tests/Gitonomy/Git/Tests/AbstractTest.php @@ -117,7 +117,7 @@ public static function createTempDir() * * @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); diff --git a/tests/Gitonomy/Git/Tests/AdminTest.php b/tests/Gitonomy/Git/Tests/AdminTest.php index 7234bdf..3bd29f5 100644 --- a/tests/Gitonomy/Git/Tests/AdminTest.php +++ b/tests/Gitonomy/Git/Tests/AdminTest.php @@ -21,14 +21,20 @@ class AdminTest extends AbstractTest { private $tmpDir; - protected function setUp() + /** + * @before + */ + public function setUpTmpDir() { $this->tmpDir = self::createTempDir(); } - protected function tearDown() + /** + * @after + */ + public function tearDownTmpDir() { - $this->deleteDir(self::createTempDir()); + self::deleteDir(self::createTempDir()); } public function testBare() diff --git a/tests/Gitonomy/Git/Tests/BlobTest.php b/tests/Gitonomy/Git/Tests/BlobTest.php index 36b1d58..4b28862 100644 --- a/tests/Gitonomy/Git/Tests/BlobTest.php +++ b/tests/Gitonomy/Git/Tests/BlobTest.php @@ -30,7 +30,11 @@ public function testGetContent($repository) { $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()); + } } /** @@ -50,7 +54,12 @@ public function testNotExisting($repository) 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()); + } } /** diff --git a/tests/Gitonomy/Git/Tests/HooksTest.php b/tests/Gitonomy/Git/Tests/HooksTest.php index 597a0b4..1b09fe5 100644 --- a/tests/Gitonomy/Git/Tests/HooksTest.php +++ b/tests/Gitonomy/Git/Tests/HooksTest.php @@ -19,7 +19,10 @@ 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; @@ -52,6 +55,7 @@ public function assertHasHook($repository, $hook) $file = $this->hookPath($repository, $hook); $this->assertTrue($repository->getHooks()->has($hook), "hook $hook in repository"); + $this->assertFileExists($file, "Hook $hook is present"); } @@ -60,7 +64,12 @@ public function assertNoHook($repository, $hook) $file = $this->hookPath($repository, $hook); $this->assertFalse($repository->getHooks()->has($hook), "No hook $hook in repository"); - $this->assertFileNotExists($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"); + } } /** @@ -104,7 +113,12 @@ public function testSymlink($repository) $repository->getHooks()->setSymlink('foo', $file); $this->assertTrue(is_link($this->hookPath($repository, 'foo')), 'foo hook is a symlink'); - $this->assertEquals(str_replace('\\', '/', $file), str_replace('\\', '/', 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' + ); } /** @@ -147,6 +161,7 @@ public function testSet_Existing_ThrowsLogicException($repository) $repository->getHooks()->set('foo', 'bar'); $this->expectException(LogicException::class); + $repository->getHooks()->set('foo', 'bar'); } @@ -159,7 +174,12 @@ public function testRemove($repository) touch($file); $repository->getHooks()->remove('foo'); - $this->assertFileNotExists($file); + + if (method_exists($this, 'assertFileDoesNotExist')) { + $this->assertFileDoesNotExist($file); + } else { + $this->assertFileNotExists($file); + } } /** diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index 2cafdd2..7ff6a19 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -21,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->assertInstanceOf(Blob::class, $blob, 'getBlob() returns a Blob object'); - $this->assertContains('Foo Bar project', $blob->getContent(), 'file is correct'); + + 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'); + } } /** From 0c6af28c7f4133f5c36274b6459048086a16d571 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 30 Jul 2020 15:42:51 +0100 Subject: [PATCH 26/61] Don't need a branch alias now --- composer.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/composer.json b/composer.json index 9211620..38108cb 100644 --- a/composer.json +++ b/composer.json @@ -44,10 +44,5 @@ "suggest": { "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.2-dev" - } } } From b4c46a9a945b878f0ff9ce7422332417e7323b04 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 30 Jul 2020 15:45:19 +0100 Subject: [PATCH 27/61] Tweaked README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7aae7fc..861dcdb 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ Gitlib for Gitonomy =================== -[![Build Status](https://img.shields.io/travis/com/gitonomy/gitlib/master.svg?style=flat-square)](https://travis-ci.com/gitonomy/gitlib) -[![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=master)](https://github.styleci.io/repos/5709354) +[![Build Status](https://img.shields.io/travis/com/gitonomy/gitlib/1.2.svg?style=flat-square)](https://travis-ci.com/gitonomy/gitlib) +[![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=1.2)](https://github.styleci.io/repos/5709354?branch=1.2) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://opensource.org/licenses/MIT) -This library provides methods to access Git repository from PHP 5.6 or 7. +This library provides methods to access Git repository from PHP 5.6+. It makes shell calls, which makes it less performant than any solution. From d1fe4676bf1347c08dec84a14a4c5e7110740d72 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 30 Jul 2020 15:54:11 +0100 Subject: [PATCH 28/61] Removed old method that was never implemented --- src/Gitonomy/Git/WorkingCopy.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Gitonomy/Git/WorkingCopy.php b/src/Gitonomy/Git/WorkingCopy.php index 057253b..aed3b85 100644 --- a/src/Gitonomy/Git/WorkingCopy.php +++ b/src/Gitonomy/Git/WorkingCopy.php @@ -35,11 +35,6 @@ public function __construct(Repository $repository) } } - public function getStatus() - { - return WorkingStatus::parseOutput(); - } - public function getUntrackedFiles() { $lines = explode("\0", $this->run('status', ['--porcelain', '--untracked-files=all', '-z'])); From e7a9ddd044933d6280996b4142e79a623771ae1e Mon Sep 17 00:00:00 2001 From: "Chun-Sheng, Li" Date: Tue, 29 Dec 2020 22:08:16 +0800 Subject: [PATCH 29/61] Fix the bug for counter variable type on PR #183 (#184) Co-authored-by: Graham Campbell --- src/Gitonomy/Git/Diff/FileChange.php | 35 ++++++++++++++++++++++++++ src/Gitonomy/Git/Parser/DiffParser.php | 8 +++--- tests/Gitonomy/Git/Tests/DiffTest.php | 8 +++--- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/Gitonomy/Git/Diff/FileChange.php b/src/Gitonomy/Git/Diff/FileChange.php index 898bbb4..cca18dc 100644 --- a/src/Gitonomy/Git/Diff/FileChange.php +++ b/src/Gitonomy/Git/Diff/FileChange.php @@ -24,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; @@ -33,6 +42,9 @@ public function __construct($rangeOldStart, $rangeOldCount, $rangeNewStart, $ran $this->lines = $lines; } + /** + * @return int + */ public function getCount($type) { $result = 0; @@ -45,31 +57,49 @@ public function getCount($type) 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 [ @@ -81,6 +111,11 @@ public function toArray() ]; } + /** + * @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']); diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index 2b84df8..d58016e 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -97,10 +97,10 @@ protected function doParse() // 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(); diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index ec0eebe..08f2e94 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -134,10 +134,10 @@ public function testDiffRangeParse($repository) $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()); } } From 69c50da21415ff9cfa73ad796032d39ecf6a1170 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 29 Dec 2020 16:46:31 +0000 Subject: [PATCH 30/61] Switch to GitHub Actions --- .github/workflows/tests.yml | 74 +++++++++++++++++++++++++++++++++++++ .travis.yml | 63 ------------------------------- README.md | 3 +- 3 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6acf5b9 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,74 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + tests: + name: PHP ${{ matrix.php }}; Symfony ${{ matrix.laravel }} + runs-on: ubuntu-20.04 + + strategy: + matrix: + php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] + symfony: ['3', '4', '5'] + exclude: + - php: '5.6' + symfony: '4' + - php: '5.6' + symfony: '5' + - php: '7.0' + symfony: '4' + - php: '7.0' + symfony: '5' + - php: '7.1' + symfony: '5' + + 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.2" --no-update --no-interaction + if: "matrix.symfony == '5'" + + - 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 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6b17e26..0000000 --- a/.travis.yml +++ /dev/null @@ -1,63 +0,0 @@ -language: php - -matrix: - include: - - php: 5.6 - dist: xenial - env: SYMFONY_VERSION=^3.4 - - php: 7.0 - dist: xenial - env: SYMFONY_VERSION=^3.4 - - php: 7.1 - dist: bionic - env: SYMFONY_VERSION=^3.4 - - php: 7.1 - dist: bionic - env: SYMFONY_VERSION=^4.0 - - php: 7.2 - dist: bionic - env: SYMFONY_VERSION=^3.4 - - php: 7.2 - dist: bionic - env: SYMFONY_VERSION=^4.0 - - php: 7.2 - dist: bionic - env: SYMFONY_VERSION=^5.0 - - php: 7.3 - dist: bionic - env: SYMFONY_VERSION=^3.4 - - php: 7.3 - dist: bionic - env: SYMFONY_VERSION=^4.0 - - php: 7.3 - dist: bionic - env: SYMFONY_VERSION=^5.0 - - php: 7.4 - dist: bionic - env: SYMFONY_VERSION=^3.4 - - php: 7.4 - dist: bionic - env: SYMFONY_VERSION=^4.0 - - php: 7.4 - dist: bionic - env: SYMFONY_VERSION=^5.0 - - php: nightly - dist: bionic - env: SYMFONY_VERSION=^3.4 - - php: nightly - dist: bionic - env: SYMFONY_VERSION=^4.0 - - php: nightly - dist: bionic - env: SYMFONY_VERSION=^5.0 - -before_install: - - composer self-update --2 - - travis_retry composer require "symfony/process:${SYMFONY_VERSION}" --no-update - -install: - - if [[ "$TRAVIS_PHP_VERSION" != 'nightly' ]]; then travis_retry composer update --prefer-dist --no-progress -n -o; fi - - if [[ "$TRAVIS_PHP_VERSION" = 'nightly' ]]; then travis_retry composer update --ignore-platform-req=php --prefer-dist --no-progress -n -o; fi - -script: - - vendor/bin/phpunit diff --git a/README.md b/README.md index 861dcdb..ddb7135 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ Gitlib for Gitonomy =================== -[![Build Status](https://img.shields.io/travis/com/gitonomy/gitlib/1.2.svg?style=flat-square)](https://travis-ci.com/gitonomy/gitlib) +[![Build Status](https://img.shields.io/github/workflow/status/gitonomy/gitlib/Tests/1.2?label=Tests&style=flat-square)](https://github.com/gitonomy/gitlib/actions?query=workflow%3ATests+branch%3A1.2) [![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=1.2)](https://github.styleci.io/repos/5709354?branch=1.2) [![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 5.6+. From d22f212b97fdb631ac73dfae65c194dc4cb0d227 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 29 Dec 2020 16:48:45 +0000 Subject: [PATCH 31/61] Updated docs --- .github/CONTRIBUTING.md | 2 +- .github/workflows/tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7c8267d..30aa95b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -28,5 +28,5 @@ $ 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 [Travis CI](https://travis-ci.org/) against pull requests. +* The tests will be automatically run by [GitHub Actions](https://github.com/features/actions) against pull requests. * We also have [StyleCI](https://styleci.io/) setup to automatically fix any code style issues. diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6acf5b9..ac7e4e4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,7 +6,7 @@ on: jobs: tests: - name: PHP ${{ matrix.php }}; Symfony ${{ matrix.laravel }} + name: PHP ${{ matrix.php }}; Symfony ${{ matrix.symfony }} runs-on: ubuntu-20.04 strategy: From e096edbdb88ac7cf2e27113f9b9b1f410a2891a8 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 4 Sep 2021 21:05:52 +0100 Subject: [PATCH 32/61] Support Symfony 6 and PHP 8.1 --- .github/CODE_OF_CONDUCT.md | 152 ++++++++++++++++++++++++------------ .github/CONTRIBUTING.md | 2 +- .github/SECURITY.md | 19 ++--- .github/workflows/tests.yml | 28 ++++++- README.md | 6 +- composer.json | 13 ++- src/Gitonomy/Git/Blame.php | 1 + src/Gitonomy/Git/Log.php | 2 + 8 files changed, 151 insertions(+), 72 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 72084f8..590c959 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -2,75 +2,131 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +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 creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* 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 by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* 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 electronic - address, without explicit permission +* 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 + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +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. -Project maintainers 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, or to ban temporarily or -permanently any contributor for other behaviors 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 both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +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 by contacting the project team at graham@alt-three.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +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. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +**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 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +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]. -[homepage]: https://www.contributor-covenant.org +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 -https://www.contributor-covenant.org/faq +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 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 30aa95b..4e3d0d6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ We accept contributions via pull requests on Github. Please review these guideli ## Guidelines -* Please follow the [PSR-2 Coding Style Guide](https://www.php-fig.org/psr/psr-2/), enforced by [StyleCI](https://styleci.io/). +* 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 individual 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. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 79a128e..8f66b91 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -2,20 +2,13 @@ ## Supported Versions -After each new major (minor) release, the previous release will be supported -for no less than 12 (6) months, unless explictly otherwise. This may mean that -there are multiple supported versions at any given time. +After each new major release, the previous release will be supported for no +less than 1 year, 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 one the security contacts. All security vulnerabilities will be -promptly addressed. Please do not disclose security-related issues publicly -until a fix has been announced. - -### Security Contacts - -* Graham Campbell (graham@alt-three.com) -* Julien Didier (genzo.wm@gmail.com) -* Grégoire Pineau (lyrixx@lyrixx.info) -* Alexandre Salomé (alexandre.salome@gmail.com) +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. diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ac7e4e4..34cc660 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,19 +11,33 @@ jobs: strategy: matrix: - php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] - symfony: ['3', '4', '5'] + 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 @@ -60,9 +74,17 @@ jobs: with: timeout_minutes: 5 max_attempts: 5 - command: composer require "symfony/process:^5.2" --no-update --no-interaction + 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: diff --git a/README.md b/README.md index ddb7135..333cc6d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ Gitlib for Gitonomy =================== -[![Build Status](https://img.shields.io/github/workflow/status/gitonomy/gitlib/Tests/1.2?label=Tests&style=flat-square)](https://github.com/gitonomy/gitlib/actions?query=workflow%3ATests+branch%3A1.2) -[![StyleCI](https://github.styleci.io/repos/5709354/shield?branch=1.2)](https://github.styleci.io/repos/5709354?branch=1.2) +[![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) @@ -26,7 +26,7 @@ or edit your `composer.json` file by hand: ```json { "require": { - "gitonomy/gitlib": "^1.2" + "gitonomy/gitlib": "^1.3" } } ``` diff --git a/composer.json b/composer.json index 38108cb..db5efe8 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" }, { "name": "Julien Didier", @@ -34,15 +34,20 @@ "php": "^5.6 || ^7.0 || ^8.0", "ext-pcre": "*", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4 || ^4.0 || ^5.0" + "symfony/process": "^3.4 || ^4.4 || ^5.0 || ^6.0" }, "require-dev": { "ext-fileinfo": "*", - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.20 || ^9.5.9", "psr/log": "^1.0" }, "suggest": { "ext-fileinfo": "Required to determine the mimetype of a blob", "psr/log": "Required to use loggers for reporting of execution" - } + }, + "config": { + "preferred-install": "dist" + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/src/Gitonomy/Git/Blame.php b/src/Gitonomy/Git/Blame.php index 17d8bfe..a9667cb 100644 --- a/src/Gitonomy/Git/Blame.php +++ b/src/Gitonomy/Git/Blame.php @@ -139,6 +139,7 @@ public function getLines() /** * @return int */ + #[\ReturnTypeWillChange] public function count() { return count($this->getLines()); diff --git a/src/Gitonomy/Git/Log.php b/src/Gitonomy/Git/Log.php index 13f1fb0..84b8bca 100644 --- a/src/Gitonomy/Git/Log.php +++ b/src/Gitonomy/Git/Log.php @@ -202,6 +202,7 @@ public function getCommits() /** * @see Countable */ + #[\ReturnTypeWillChange] public function count() { return $this->countCommits(); @@ -210,6 +211,7 @@ public function count() /** * @see IteratorAggregate */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->getCommits()); From ed15dba0aa042bad925a4b26655f57d398d3f4aa Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 6 Sep 2021 20:45:36 +0100 Subject: [PATCH 33/61] Added missing `ReturnTypeWillChange` annotations --- src/Gitonomy/Git/ReferenceBag.php | 2 ++ src/Gitonomy/Git/RevisionList.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Gitonomy/Git/ReferenceBag.php b/src/Gitonomy/Git/ReferenceBag.php index 57aec25..35fd710 100644 --- a/src/Gitonomy/Git/ReferenceBag.php +++ b/src/Gitonomy/Git/ReferenceBag.php @@ -375,6 +375,7 @@ protected function initialize() * * @see Countable */ + #[\ReturnTypeWillChange] public function count() { $this->initialize(); @@ -385,6 +386,7 @@ public function count() /** * @see IteratorAggregate */ + #[\ReturnTypeWillChange] public function getIterator() { $this->initialize(); diff --git a/src/Gitonomy/Git/RevisionList.php b/src/Gitonomy/Git/RevisionList.php index 760abb6..a3dfe59 100644 --- a/src/Gitonomy/Git/RevisionList.php +++ b/src/Gitonomy/Git/RevisionList.php @@ -54,11 +54,13 @@ public function getAll() return $this->revisions; } + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->revisions); } + #[\ReturnTypeWillChange] public function count() { return count($this->revisions); From e73e439590b194b0b250b516b22a68c7116e2f21 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 6 Sep 2021 21:30:10 +0100 Subject: [PATCH 34/61] Fixed passing null to integer param --- src/Gitonomy/Git/Parser/ParserBase.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Gitonomy/Git/Parser/ParserBase.php b/src/Gitonomy/Git/Parser/ParserBase.php index 94155ce..7ce1eae 100644 --- a/src/Gitonomy/Git/Parser/ParserBase.php +++ b/src/Gitonomy/Git/Parser/ParserBase.php @@ -59,7 +59,7 @@ protected function expects($expected) 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)); } @@ -70,7 +70,7 @@ protected function consumeShortHash() 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)); } @@ -81,7 +81,7 @@ protected function consumeHash() protected function consumeRegexp($regexp) { - if (!preg_match($regexp.'A', $this->content, $vars, null, $this->cursor)) { + 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, 30)); } From 13cd2b134c5371bfc8ab051628193607ce4d6f30 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Mon, 18 Oct 2021 00:26:47 +0100 Subject: [PATCH 35/61] Updated contribution docs (#187) --- .github/CONTRIBUTING.md | 10 +++++----- .github/SECURITY.md | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4e3d0d6..d33db7e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,16 +2,16 @@ Contributions are **welcome** and will be fully **credited**. -We accept contributions via pull requests on Github. Please review these guidelines before continuing. +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 individual commit in your pull request is meaningful. +* 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 [SemVer](https://semver.org/). +* 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 @@ -29,4 +29,4 @@ $ 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/) setup to automatically fix any code style issues. +* We also have [StyleCI](https://styleci.io/) set up to automatically fix any code style issues. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 8f66b91..0c3e8a2 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -3,8 +3,8 @@ ## Supported Versions After each new major release, the previous release will be supported for no -less than 1 year, unless explictly stated otherwise. This may mean that there -are multiple supported versions at any given time. +less than 12 months, unless explictly stated otherwise. This may mean that +there are multiple supported versions at any given time. ## Reporting a Vulnerability From 1238d31d07a9fac94547c5a5a07efafce9eaf03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Salom=C3=A9?= Date: Fri, 10 Dec 2021 12:12:26 +0100 Subject: [PATCH 36/61] Add missing use statement (#188) --- src/Gitonomy/Git/Reference/Tag.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Gitonomy/Git/Reference/Tag.php b/src/Gitonomy/Git/Reference/Tag.php index f8461e1..988ac1e 100644 --- a/src/Gitonomy/Git/Reference/Tag.php +++ b/src/Gitonomy/Git/Reference/Tag.php @@ -12,6 +12,7 @@ namespace Gitonomy\Git\Reference; +use Gitonomy\Git\Commit; use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\RuntimeException; use Gitonomy\Git\Parser\ReferenceParser; From 2c72667295954dfcdeffb32024d00e1be8631c73 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 23 Jan 2022 20:23:58 +0000 Subject: [PATCH 37/61] `convertDeprecationsToExceptions="true"` (#189) --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fd8be6a..77fe623 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,6 +5,7 @@ beStrictAboutOutputDuringTests="true" bootstrap="tests/bootstrap.php" colors="true" + convertDeprecationsToExceptions="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" From 5035f69c06df74ab7ee8ec14da9016b71ff3ed50 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 23 Jan 2022 20:26:42 +0000 Subject: [PATCH 38/61] Update composer.json --- composer.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index db5efe8..417c763 100644 --- a/composer.json +++ b/composer.json @@ -5,19 +5,23 @@ "authors": [ { "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { "name": "Julien Didier", - "email": "genzo.wm@gmail.com" + "email": "genzo.wm@gmail.com", + "homepage": "https://github.com/juliendidier" }, { "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" + "email": "lyrixx@lyrixx.info", + "homepage": "https://github.com/lyrixx" }, { "name": "Alexandre Salomé", - "email": "alexandre.salome@gmail.com" + "email": "alexandre.salome@gmail.com", + "homepage": "https://github.com/alexandresalome" } ], "autoload": { From 3c2f67a2fa6e7b26dbc9b9d0ca272ed33ba5895e Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Mon, 14 Feb 2022 02:07:07 -0700 Subject: [PATCH 39/61] Don't pass null as second parameter to preg_match (#190) --- src/Gitonomy/Git/Parser/DiffParser.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index d58016e..edaea1e 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -90,6 +90,8 @@ protected function doParse() $oldName = $oldName === '/dev/null' ? null : substr($oldName, 2); $newName = $newName === '/dev/null' ? null : substr($newName, 2); + $oldIndex !== null ?: ''; + $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); From 793ffe5826c30e64ea499ea9e4bb353dd0892bef Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 1 Mar 2022 05:56:00 -0500 Subject: [PATCH 40/61] Assign to variable to prevent null value (#192) --- src/Gitonomy/Git/Parser/DiffParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index edaea1e..3fa9e2e 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -90,8 +90,8 @@ protected function doParse() $oldName = $oldName === '/dev/null' ? null : substr($oldName, 2); $newName = $newName === '/dev/null' ? null : substr($newName, 2); - $oldIndex !== null ?: ''; - $newIndex !== null ?: ''; + $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); From 33ae0a2e469accc19d1a06bed63ed93dbf368ae2 Mon Sep 17 00:00:00 2001 From: Anatolij Vasilev <3026792+tolik518@users.noreply.github.com> Date: Fri, 5 Aug 2022 11:17:13 +0200 Subject: [PATCH 41/61] Added more type hinting & Fixed bug when parsing renamed files with spaces and/or non english-symbols (#194) * changed repo name in the composer * added path to the symlink RuntimeException exception-message * added more and better typehints into PHPDocs above methods * Regex didn't count for the rare case when the diff has quotation marks around the filenames (file names with non-english symbols for example) * replaced uninitialized $entry variable with $element * removed getRevisions() since revisions isn't a part of the Diff object * removed unused $fullname in the getCommit() method * - added more type hinting - introduced data property to Tag - added .idea to .gitignore * - changes that were requested by " continuous-integration/styleci/pr" - fixed composer.json * upped the number of characters that are shown to get a more verbose exception * added type annotation for file in the Diff class * - fixed parser to properly work with files - with umlauts added a test - made changes @lyrixx suggested * - made fixes for @continuous-integration/styleci/pr * - made one more fix for @continuous-integration/styleci/pr * - switches quotes for @continuous-integration/styleci/pr * added trailing \n to the gitignore --- src/Gitonomy/Git/Blame.php | 4 +- src/Gitonomy/Git/Blob.php | 4 +- src/Gitonomy/Git/Commit.php | 18 ++++++--- src/Gitonomy/Git/CommitReference.php | 3 ++ src/Gitonomy/Git/Diff/Diff.php | 12 +----- src/Gitonomy/Git/Diff/File.php | 8 +++- src/Gitonomy/Git/Hooks.php | 8 +++- src/Gitonomy/Git/Log.php | 6 ++- src/Gitonomy/Git/Parser/DiffParser.php | 10 +++-- src/Gitonomy/Git/Parser/ParserBase.php | 2 +- src/Gitonomy/Git/PushReference.php | 9 ++++- src/Gitonomy/Git/Reference.php | 19 ++++++++-- src/Gitonomy/Git/Reference/Tag.php | 8 ++-- src/Gitonomy/Git/ReferenceBag.php | 51 ++++++++++++++++---------- src/Gitonomy/Git/Repository.php | 3 ++ src/Gitonomy/Git/RevisionList.php | 3 ++ src/Gitonomy/Git/Tree.php | 2 +- tests/Gitonomy/Git/Tests/DiffTest.php | 10 +++++ 18 files changed, 123 insertions(+), 57 deletions(-) diff --git a/src/Gitonomy/Git/Blame.php b/src/Gitonomy/Git/Blame.php index a9667cb..dec0773 100644 --- a/src/Gitonomy/Git/Blame.php +++ b/src/Gitonomy/Git/Blame.php @@ -108,9 +108,7 @@ public function getGroupedLines() } /** - * Returns all lines of the blame. - * - * @return array + * @return Line[] All lines of the blame. */ public function getLines() { diff --git a/src/Gitonomy/Git/Blob.php b/src/Gitonomy/Git/Blob.php index 1015093..e455fe2 100644 --- a/src/Gitonomy/Git/Blob.php +++ b/src/Gitonomy/Git/Blob.php @@ -58,9 +58,9 @@ public function getHash() } /** - * Returns content of the blob. - * * @throws ProcessException Error occurred while getting content of blob + * + * @return string Content of the blob. */ public function getContent() { diff --git a/src/Gitonomy/Git/Commit.php b/src/Gitonomy/Git/Commit.php index 10141be..2008f7a 100644 --- a/src/Gitonomy/Git/Commit.php +++ b/src/Gitonomy/Git/Commit.php @@ -16,6 +16,7 @@ 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; /** @@ -35,8 +36,8 @@ class Commit extends Revision /** * 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 = []) { @@ -91,6 +92,8 @@ public function getShortHash() /** * Returns a fixed-with short hash. + * + * @return string Short hash */ public function getFixedShortHash($length = 6) { @@ -100,7 +103,7 @@ public function getFixedShortHash($length = 6) /** * Returns parent hashes. * - * @return array An array of SHA1 hashes + * @return string[] An array of SHA1 hashes */ public function getParentHashes() { @@ -110,7 +113,7 @@ public function getParentHashes() /** * Returns the parent commits. * - * @return array An array of Commit objects + * @return Commit[] An array of Commit objects */ public function getParents() { @@ -132,6 +135,9 @@ public function getTreeHash() return $this->getData('treeHash'); } + /** + * @return Tree + */ public function getTree() { return $this->getData('tree'); @@ -184,7 +190,7 @@ public function getShortMessage($length = 50, $preserve = false, $separator = '. /** * 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() { @@ -197,7 +203,7 @@ public function resolveReferences() * @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) { diff --git a/src/Gitonomy/Git/CommitReference.php b/src/Gitonomy/Git/CommitReference.php index bb20bc3..7be3d89 100644 --- a/src/Gitonomy/Git/CommitReference.php +++ b/src/Gitonomy/Git/CommitReference.php @@ -14,6 +14,9 @@ class CommitReference { + /** + * @var string + */ private $hash; public function __construct($hash) diff --git a/src/Gitonomy/Git/Diff/Diff.php b/src/Gitonomy/Git/Diff/Diff.php index faafbcb..7737ee8 100644 --- a/src/Gitonomy/Git/Diff/Diff.php +++ b/src/Gitonomy/Git/Diff/Diff.php @@ -23,7 +23,7 @@ class Diff { /** - * @var array + * @var File[] */ protected $files; @@ -62,18 +62,10 @@ public function setRepository(Repository $repository) } } - /** - * @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() { diff --git a/src/Gitonomy/Git/Diff/File.php b/src/Gitonomy/Git/Diff/File.php index f709976..d3da24b 100644 --- a/src/Gitonomy/Git/Diff/File.php +++ b/src/Gitonomy/Git/Diff/File.php @@ -55,7 +55,7 @@ class File protected $isBinary; /** - * @var array An array of FileChange objects + * @var FileChange[] An array of FileChange objects */ protected $changes; @@ -215,6 +215,9 @@ public function isBinary() return $this->isBinary; } + /** + * @return FileChange[] + */ public function getChanges() { return $this->changes; @@ -236,6 +239,9 @@ public function toArray() ]; } + /** + * @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']); diff --git a/src/Gitonomy/Git/Hooks.php b/src/Gitonomy/Git/Hooks.php index 3c19d2c..dd0adbe 100644 --- a/src/Gitonomy/Git/Hooks.php +++ b/src/Gitonomy/Git/Hooks.php @@ -14,6 +14,7 @@ use Gitonomy\Git\Exception\InvalidArgumentException; use Gitonomy\Git\Exception\LogicException; +use Gitonomy\Git\Exception\RuntimeException; /** * Hooks collection, aggregated by repository. @@ -23,7 +24,7 @@ class Hooks { /** - * @var Gitonomy\Git\Repository + * @var \Gitonomy\Git\Repository */ protected $repository; @@ -82,7 +83,7 @@ public function setSymlink($name, $file) $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)); } } @@ -121,6 +122,9 @@ public function remove($name) unlink($this->getPath($name)); } + /** + * @return string + */ protected function getPath($name) { return $this->repository->getGitDir().'/hooks/'.$name; diff --git a/src/Gitonomy/Git/Log.php b/src/Gitonomy/Git/Log.php index 84b8bca..4766535 100644 --- a/src/Gitonomy/Git/Log.php +++ b/src/Gitonomy/Git/Log.php @@ -12,6 +12,7 @@ namespace Gitonomy\Git; +use Gitonomy\Git\Diff\Diff; use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\ReferenceNotFoundException; use Gitonomy\Git\Util\StringHelper; @@ -136,6 +137,9 @@ public function setLimit($limit) return $this; } + /** + * @return Commit + */ public function getSingleCommit() { $limit = $this->limit; @@ -151,7 +155,7 @@ public function getSingleCommit() } /** - * @return array + * @return Commit[] */ public function getCommits() { diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index 3fa9e2e..e14f879 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -25,7 +25,7 @@ protected function doParse() 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; @@ -74,14 +74,15 @@ protected function doParse() } $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]; @@ -90,6 +91,7 @@ protected function doParse() $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; diff --git a/src/Gitonomy/Git/Parser/ParserBase.php b/src/Gitonomy/Git/Parser/ParserBase.php index 7ce1eae..7cd37e7 100644 --- a/src/Gitonomy/Git/Parser/ParserBase.php +++ b/src/Gitonomy/Git/Parser/ParserBase.php @@ -82,7 +82,7 @@ protected function consumeHash() protected function consumeRegexp($regexp) { 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, 30)); + throw new RuntimeException('No match for regexp '.$regexp.' Upcoming: '.substr($this->content, $this->cursor, 500)); } $this->cursor += strlen($vars[0]); diff --git a/src/Gitonomy/Git/PushReference.php b/src/Gitonomy/Git/PushReference.php index 3911bd2..dea1082 100644 --- a/src/Gitonomy/Git/PushReference.php +++ b/src/Gitonomy/Git/PushReference.php @@ -24,6 +24,10 @@ class PushReference { const ZERO = '0000000000000000000000000000000000000000'; + /** + * @var Repository + */ + protected $repository; /** * @var string */ @@ -86,7 +90,7 @@ public function getAfter() } /** - * @return array + * @return Log */ public function getLog($excludes = []) { @@ -98,6 +102,9 @@ public function getLog($excludes = []) )); } + /** + * @return string + */ public function getRevision() { if ($this->isDelete()) { diff --git a/src/Gitonomy/Git/Reference.php b/src/Gitonomy/Git/Reference.php index 23f1cb7..96b8fa1 100644 --- a/src/Gitonomy/Git/Reference.php +++ b/src/Gitonomy/Git/Reference.php @@ -12,6 +12,9 @@ namespace Gitonomy\Git; +use Gitonomy\Git\Exception\ProcessException; +use Gitonomy\Git\Exception\ReferenceNotFoundException; + /** * Reference in a Git repository. * @@ -29,16 +32,25 @@ public function __construct(Repository $repository, $revision, $commitHash = nul $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) { @@ -55,15 +67,16 @@ public function getCommitHash() } /** - * 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); diff --git a/src/Gitonomy/Git/Reference/Tag.php b/src/Gitonomy/Git/Reference/Tag.php index 988ac1e..bca6ca4 100644 --- a/src/Gitonomy/Git/Reference/Tag.php +++ b/src/Gitonomy/Git/Reference/Tag.php @@ -27,6 +27,8 @@ */ class Tag extends Reference { + protected $data; + public function getName() { if (!preg_match('#^refs/tags/(.*)$#', $this->revision, $vars)) { @@ -65,8 +67,8 @@ public function getCommit() $parser = new ReferenceParser(); $parser->parse($output); - foreach ($parser->references as $row) { - list($commitHash, $fullname) = $row; + foreach ($parser->references as list($row)) { + $commitHash = $row; } return $this->repository->getCommit($commitHash); @@ -101,7 +103,7 @@ public function getTaggerEmail() /** * Returns the authoring date. * - * @return DateTime A time object + * @return \DateTime A time object */ public function getTaggerDate() { diff --git a/src/Gitonomy/Git/ReferenceBag.php b/src/Gitonomy/Git/ReferenceBag.php index 35fd710..4b79fc6 100644 --- a/src/Gitonomy/Git/ReferenceBag.php +++ b/src/Gitonomy/Git/ReferenceBag.php @@ -29,7 +29,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate /** * Repository object. * - * @var Gitonomy\Git\Repository + * @var Repository */ protected $repository; @@ -43,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; @@ -64,7 +64,7 @@ class ReferenceBag implements \Countable, \IteratorAggregate /** * Constructor. * - * @param Gitonomy\Git\Repository $repository The repository + * @param Repository $repository The repository */ public function __construct($repository) { @@ -92,6 +92,9 @@ public function get($fullname) return $this->references[$fullname]; } + /** + * @return bool + */ public function has($fullname) { $this->initialize(); @@ -99,6 +102,9 @@ public function has($fullname) return isset($this->references[$fullname]); } + /** + * @return Reference + */ public function update(Reference $reference) { $fullname = $reference->getFullname(); @@ -111,6 +117,9 @@ public function update(Reference $reference) return $reference; } + /** + * @return Reference + */ public function createBranch($name, $commitHash) { $branch = new Branch($this->repository, 'refs/heads/'.$name, $commitHash); @@ -118,6 +127,9 @@ public function createBranch($name, $commitHash) return $this->update($branch); } + /** + * @return Reference + */ public function createTag($name, $commitHash) { $tag = new Tag($this->repository, 'refs/tags/'.$name, $commitHash); @@ -125,6 +137,9 @@ public function createTag($name, $commitHash) return $this->update($tag); } + /** + * @return void + */ public function delete($fullname) { $this->repository->run('update-ref', ['-d', $fullname]); @@ -132,6 +147,9 @@ public function delete($fullname) unset($this->references[$fullname]); } + /** + * @return bool + */ public function hasBranches() { $this->initialize(); @@ -154,6 +172,9 @@ public function hasTag($name) return $this->has('refs/tags/'.$name); } + /** + * @return Branch + */ public function getFirstBranch() { $this->initialize(); @@ -163,7 +184,7 @@ public function getFirstBranch() } /** - * @return array An array of Tag objects + * @return Tag[] An array of Tag objects */ public function resolveTags($hash) { @@ -184,7 +205,7 @@ public function resolveTags($hash) } /** - * @return array An array of Branch objects + * @return Branch[] An array of Branch objects */ public function resolveBranches($hash) { @@ -205,7 +226,7 @@ public function resolveBranches($hash) } /** - * @return array An array of references + * @return Reference[] An array of references */ public function resolve($hash) { @@ -226,9 +247,7 @@ public function resolve($hash) } /** - * Returns all tags. - * - * @return array + * @return Tag[] All tags. */ public function getTags() { @@ -238,9 +257,7 @@ public function getTags() } /** - * Returns all branches. - * - * @return array + * @return Branch[] All branches. */ public function getBranches() { @@ -257,9 +274,7 @@ public function getBranches() } /** - * Returns all locales branches. - * - * @return array + * @return Branch[] All local branches. */ public function getLocalBranches() { @@ -274,9 +289,7 @@ public function getLocalBranches() } /** - * Returns all remote branches. - * - * @return array + * @return Branch[] All remote branches. */ public function getRemoteBranches() { diff --git a/src/Gitonomy/Git/Repository.php b/src/Gitonomy/Git/Repository.php index 3920616..fe77a88 100644 --- a/src/Gitonomy/Git/Repository.php +++ b/src/Gitonomy/Git/Repository.php @@ -376,6 +376,9 @@ public function getBlob($hash) return $this->objects[$hash]; } + /** + * @return Blame + */ public function getBlame($revision, $file, $lineRange = null) { if (is_string($revision)) { diff --git a/src/Gitonomy/Git/RevisionList.php b/src/Gitonomy/Git/RevisionList.php index a3dfe59..1c1a1dc 100644 --- a/src/Gitonomy/Git/RevisionList.php +++ b/src/Gitonomy/Git/RevisionList.php @@ -49,6 +49,9 @@ public function __construct(Repository $repository, $revisions) $this->revisions = $revisions; } + /** + * @return Revision[] + */ public function getAll() { return $this->revisions; diff --git a/src/Gitonomy/Git/Tree.php b/src/Gitonomy/Git/Tree.php index d317983..570c8ff 100644 --- a/src/Gitonomy/Git/Tree.php +++ b/src/Gitonomy/Git/Tree.php @@ -96,7 +96,7 @@ public function resolvePath($path) 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'); diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index 08f2e94..e251d72 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -20,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 @@ -140,4 +141,13 @@ public function testDiffRangeParse($repository) $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()); + } } From 00b57b79f02396aa4c7c163f76fe2bc48faebbb7 Mon Sep 17 00:00:00 2001 From: Anatolij Vasilev <3026792+tolik518@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:20:15 +0200 Subject: [PATCH 42/61] Added tests for empty commit messages (#196) * added tests for empty commit messages * cosmetic changes for continuous-integration/styleci/pr * added phpspec/prophecy to composer-json, so the tests pass * added phpspec/prophecy compatibility with php 5.6 * sorted composer.json alphabetically and removed "^1.15" --- composer.json | 1 + tests/Gitonomy/Git/Tests/AbstractTest.php | 1 + tests/Gitonomy/Git/Tests/CommitTest.php | 26 +++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/composer.json b/composer.json index 417c763..86735c1 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ }, "require-dev": { "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" }, diff --git a/tests/Gitonomy/Git/Tests/AbstractTest.php b/tests/Gitonomy/Git/Tests/AbstractTest.php index d586eda..0b9a51b 100644 --- a/tests/Gitonomy/Git/Tests/AbstractTest.php +++ b/tests/Gitonomy/Git/Tests/AbstractTest.php @@ -20,6 +20,7 @@ abstract class AbstractTest extends TestCase { 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'; diff --git a/tests/Gitonomy/Git/Tests/CommitTest.php b/tests/Gitonomy/Git/Tests/CommitTest.php index 8dca9c4..7d09464 100644 --- a/tests/Gitonomy/Git/Tests/CommitTest.php +++ b/tests/Gitonomy/Git/Tests/CommitTest.php @@ -16,6 +16,7 @@ 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 @@ -189,6 +190,31 @@ public function testGetMessage($repository) $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. From f9b36538fc784782f3b960655722c996b55624de Mon Sep 17 00:00:00 2001 From: Anatolij Vasilev <3026792+tolik518@users.noreply.github.com> Date: Tue, 8 Nov 2022 07:21:31 +0100 Subject: [PATCH 43/61] Method to check if a branch is merged (added code from PR #151) (#197) * added code from PR #151 * added user credentials which are needed for the next commands * stylistic changes to satisfy style-ci * moved user credentials to the top * stylistic changes to satisfy style-ci --- src/Gitonomy/Git/Reference/Branch.php | 45 ++++++++++++++++++++++ tests/Gitonomy/Git/Tests/ReferenceTest.php | 28 ++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/Gitonomy/Git/Reference/Branch.php b/src/Gitonomy/Git/Reference/Branch.php index 0f263a7..0d27fb8 100644 --- a/src/Gitonomy/Git/Reference/Branch.php +++ b/src/Gitonomy/Git/Reference/Branch.php @@ -12,8 +12,10 @@ namespace Gitonomy\Git\Reference; +use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\RuntimeException; use Gitonomy\Git\Reference; +use Gitonomy\Git\Util\StringHelper; /** * Representation of a branch reference. @@ -53,6 +55,49 @@ public function isLocal() return $this->local; } + /** + * Check if this branch is merged to a destination branch + * Optionally, check only with remote branches. + * + * @param string $destinationBranchName + * @param bool $compareOnlyWithRemote + * + * @return null|bool + */ + public function isMergedTo($destinationBranchName = 'master', $compareOnlyWithRemote = false) + { + $arguments = ['-a']; + + if ($compareOnlyWithRemote) { + $arguments = ['-r']; + } + + $arguments[] = '--merged'; + $arguments[] = $destinationBranchName; + + try { + $result = $this->repository->run('branch', $arguments); + } catch (ProcessException $e) { + throw new RuntimeException( + sprintf('Cannot determine if merged to the branch "%s"', $destinationBranchName), + $e->getCode(), + $e + ); + } + + if (!$result) { + return false; + } + + $output = explode("\n", trim(str_replace(['*', 'remotes/'], '', $result))); + $filtered_output = array_filter($output, static function ($v) { + return false === StringHelper::strpos($v, '->'); + }); + $trimmed_output = array_map('trim', $filtered_output); + + return in_array($this->getName(), $trimmed_output, true); + } + private function detectBranchType() { if (null === $this->local) { diff --git a/tests/Gitonomy/Git/Tests/ReferenceTest.php b/tests/Gitonomy/Git/Tests/ReferenceTest.php index d24a5e6..0f97557 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceTest.php @@ -209,4 +209,32 @@ public function testCreateAndDeleteBranch($repository) $branch->delete(); $this->assertFalse($references->hasBranch('foobar'), 'Branch foobar removed'); } + + /** + * @dataProvider provideFoobar + */ + public function testIsBranchMergedToMaster() + { + $repository = self::createFoobarRepository(false); + + $repository->run('config', ['--local', 'user.name', '"Unit Test"']); + $repository->run('config', ['--local', 'user.email', '"unit_test@unit-test.com"']); + + $master = $repository->getReferences()->getBranch('master'); + $references = $repository->getReferences(); + + $branch = $references->createBranch('foobar-new', $master->getCommit()->getHash()); + + $this->assertTrue($branch->isMergedTo('master')); + + $wc = $repository->getWorkingCopy(); + $wc->checkout('foobar-new'); + + $file = $repository->getWorkingDir().'/foobar-test.txt'; + file_put_contents($file, 'test'); + $repository->run('add', [$file]); + $repository->run('commit', ['-m', 'foobar-test.txt updated']); + + $this->assertFalse($branch->isMergedTo('master')); + } } From 11a3dfc80a031ed646ba38b4a45e54cb883e57c1 Mon Sep 17 00:00:00 2001 From: Anatolij Vasilev <3026792+tolik518@users.noreply.github.com> Date: Tue, 3 Jan 2023 14:04:26 +0100 Subject: [PATCH 44/61] fixed github test badge: https://github.com/badges/shields/issues/8671 (#199) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 333cc6d..e0dcade 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Gitlib for Gitonomy =================== -[![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) +[![Build Status](https://img.shields.io/github/actions/workflow/status/gitonomy/gitlib/tests.yml?label=Tests&style=flat-square&branch=1.3)](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) From 9fea656e75ad6e3452feb2cac46a6c1239cd7f74 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Thu, 11 May 2023 10:29:06 +0200 Subject: [PATCH 45/61] Adds feature to check if a branch name exists in a repository without cloning it. (#202) --- src/Gitonomy/Git/Admin.php | 24 ++++++++++++++++++++++++ tests/Gitonomy/Git/Tests/AdminTest.php | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Gitonomy/Git/Admin.php b/src/Gitonomy/Git/Admin.php index 7b64cd7..7b32794 100644 --- a/src/Gitonomy/Git/Admin.php +++ b/src/Gitonomy/Git/Admin.php @@ -67,6 +67,30 @@ public static function isValidRepository($url, array $options = []) return $process->isSuccessFul(); } + /** + * Checks the validity of a git repository url without cloning it and + * check if a certain branch exists in that repository. + * + * This will use the `ls-remote` command of git against the given url. + * Usually, this command returns 0 when successful, and 128 when the + * repository is not found. + * + * @param string $url url of repository to check + * @param string $branchName name of branch to check + * @param array $options options for Repository creation + * + * @return bool true if url is valid and branch exists + */ + public static function isValidRepositoryAndBranch($url, $branchName, array $options = []) + { + $process = static::getProcess('ls-remote', ['--heads', $url, $branchName], $options); + + $process->run(); + $processOutput = $process->getOutput(); + + return $process->isSuccessFul() && strpos($processOutput, $branchName) !== false; + } + /** * Clone a repository to a local path. * diff --git a/tests/Gitonomy/Git/Tests/AdminTest.php b/tests/Gitonomy/Git/Tests/AdminTest.php index 3bd29f5..0f7460f 100644 --- a/tests/Gitonomy/Git/Tests/AdminTest.php +++ b/tests/Gitonomy/Git/Tests/AdminTest.php @@ -155,6 +155,24 @@ public function testCheckInvalidRepository() $this->assertFalse(Admin::isValidRepository($url)); } + /** + * @dataProvider provideFoobar + */ + public function testCheckValidRepositoryAndBranch($repository) + { + $url = $repository->getGitDir(); + $this->assertTrue(Admin::isValidRepositoryAndBranch($url, 'master')); + } + + /** + * @dataProvider provideFoobar + */ + public function testCheckInvalidRepositoryAndBranch($repository) + { + $url = $repository->getGitDir(); + $this->assertFalse(Admin::isValidRepositoryAndBranch($url, 'invalid-branch-name')); + } + public function testExistingFile() { $this->expectException(RuntimeException::class); From e4e06bb9db45728a3a9f05499cb4295fd6f3bdba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 22 May 2023 17:00:21 +0200 Subject: [PATCH 46/61] Bump minimal PHP version to 8.0 (#204) * Bump minimal PHP version to 8.0 * Fixed ci when pushing on origin repo --- .github/workflows/tests.yml | 84 ++++----------------- composer.json | 15 ++-- tests/Gitonomy/Git/Tests/RepositoryTest.php | 5 +- 3 files changed, 24 insertions(+), 80 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 34cc660..79d8bf1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,42 +2,23 @@ name: Tests on: push: + branches: [ main ] pull_request: jobs: tests: - name: PHP ${{ matrix.php }}; Symfony ${{ matrix.symfony }} - runs-on: ubuntu-20.04 - + name: Test PHP ${{ matrix.php-version }} ${{ matrix.name }} + runs-on: ubuntu-latest strategy: + fail-fast: false 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' + php-version: ['8.1', '8.2'] + composer-flags: [''] + name: [''] + include: + - php: 8.0 + composer-flags: '--prefer-lowest' + name: '(prefer lowest dependencies)' steps: - name: Checkout Code @@ -47,50 +28,13 @@ jobs: 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: Install Composer dependencies + run: | + composer update --prefer-dist --no-interaction ${{ matrix.composer-flags }} - name: Execute PHPUnit run: vendor/bin/phpunit diff --git a/composer.json b/composer.json index 86735c1..fe0dd35 100644 --- a/composer.json +++ b/composer.json @@ -35,23 +35,20 @@ } }, "require": { - "php": "^5.6 || ^7.0 || ^8.0", + "php": "^8.0", "ext-pcre": "*", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4 || ^4.4 || ^5.0 || ^6.0" + "symfony/process": "^5.4 || ^6.0" }, "require-dev": { "ext-fileinfo": "*", - "phpspec/prophecy": "^1.10.2", - "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.20 || ^9.5.9", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.20 || ^9.5.9", "psr/log": "^1.0" }, - "suggest": { - "ext-fileinfo": "Required to determine the mimetype of a blob", - "psr/log": "Required to use loggers for reporting of execution" - }, "config": { - "preferred-install": "dist" + "preferred-install": "dist", + "sort-packages": true }, "minimum-stability": "dev", "prefer-stable": true diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index 7ff6a19..de433df 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -15,9 +15,12 @@ use Gitonomy\Git\Blob; use Gitonomy\Git\Exception\RuntimeException; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; class RepositoryTest extends AbstractTest { + use ProphecyTrait; + /** * @dataProvider provideFoobar */ @@ -40,7 +43,7 @@ public function testGetBlobWithExistingWorks($repository) public function testGetSize($repository) { $size = $repository->getSize(); - $this->assertGreaterThanOrEqual(69, $size, 'Repository is at least 69KB'); + $this->assertGreaterThanOrEqual(53, $size, 'Repository is at least 53KB'); $this->assertLessThan(80, $size, 'Repository is less than 80KB'); } From 2c7fbbd9814178474d0bb1b6292701cb4ab508f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Mokr=C3=BD?= <31004308+MokryPatrik@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:02:08 +0100 Subject: [PATCH 47/61] Add support for symfony 7 (#213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Mokrý --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fe0dd35..a3de053 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": "^8.0", "ext-pcre": "*", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^5.4 || ^6.0" + "symfony/process": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { "ext-fileinfo": "*", From ba22bb2ebfdfdfae9d11134072eb04cb81d3fc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20=C3=87al=C4=B1=C5=9Fkan?= <13554944+thecaliskan@users.noreply.github.com> Date: Fri, 5 Jan 2024 00:38:31 +0300 Subject: [PATCH 48/61] Added PHP 8.3 Test (#215) --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 79d8bf1..e40ff9a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['8.1', '8.2'] + php-version: ['8.1', '8.2', '8.3'] composer-flags: [''] name: [''] include: From 640068c25297fcc3b7b8948a8421d9f21fc5e0ba Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Wed, 24 Apr 2024 12:18:59 +0200 Subject: [PATCH 49/61] Detect binary file by NULL byte (#219) * Detect binary file by NULL byte * Add description where the binary check and values come from --------- Co-authored-by: Patrick Beuks --- src/Gitonomy/Git/Blob.php | 22 +++++++++++++++++++++- tests/Gitonomy/Git/Tests/BlobTest.php | 17 +++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Gitonomy/Git/Blob.php b/src/Gitonomy/Git/Blob.php index e455fe2..dfe885f 100644 --- a/src/Gitonomy/Git/Blob.php +++ b/src/Gitonomy/Git/Blob.php @@ -19,6 +19,11 @@ */ class Blob { + /** + * @var int Size that git uses to look for NULL byte: https://git.kernel.org/pub/scm/git/git.git/tree/xdiff-interface.c?h=v2.44.0#n193 + */ + private const FIRST_FEW_BYTES = 8000; + /** * @var Repository */ @@ -39,6 +44,11 @@ class Blob */ protected $mimetype; + /** + * @var bool + */ + protected $text; + /** * @param Repository $repository Repository where the blob is located * @param string $hash Hash of the blob @@ -89,6 +99,9 @@ public function getMimetype() /** * Determines if file is binary. * + * Uses the same check that git uses to determine if a file is binary or not + * https://git.kernel.org/pub/scm/git/git.git/tree/xdiff-interface.c?h=v2.44.0#n193 + * * @return bool */ public function isBinary() @@ -99,10 +112,17 @@ public function isBinary() /** * Determines if file is text. * + * Uses the same check that git uses to determine if a file is binary or not + * https://git.kernel.org/pub/scm/git/git.git/tree/xdiff-interface.c?h=v2.44.0#n193 + * * @return bool */ public function isText() { - return (bool) preg_match('#^text/|^application/xml#', $this->getMimetype()); + if (null === $this->text) { + $this->text = !str_contains(substr($this->getContent(), 0, self::FIRST_FEW_BYTES), chr(0)); + } + + return $this->text; } } diff --git a/tests/Gitonomy/Git/Tests/BlobTest.php b/tests/Gitonomy/Git/Tests/BlobTest.php index 4b28862..431a0a4 100644 --- a/tests/Gitonomy/Git/Tests/BlobTest.php +++ b/tests/Gitonomy/Git/Tests/BlobTest.php @@ -23,6 +23,11 @@ public function getReadmeBlob($repository) return $repository->getCommit(self::LONGFILE_COMMIT)->getTree()->resolvePath('README.md'); } + public function getImageBlob($repository) + { + return $repository->getCommit(self::LONGFILE_COMMIT)->getTree()->resolvePath('image.jpg'); + } + /** * @dataProvider provideFoobar */ @@ -67,8 +72,10 @@ public function testGetMimetype($repository) */ public function testIsText($repository) { - $blob = $this->getReadmeBlob($repository); - $this->assertTrue($blob->isText()); + $readmeBlob = $this->getReadmeBlob($repository); + $this->assertTrue($readmeBlob->isText()); + $imageBlob = $this->getImageBlob($repository); + $this->assertFalse($imageBlob->isText()); } /** @@ -76,7 +83,9 @@ public function testIsText($repository) */ public function testIsBinary($repository) { - $blob = $this->getReadmeBlob($repository); - $this->assertFalse($blob->isBinary()); + $readmeBlob = $this->getReadmeBlob($repository); + $this->assertFalse($readmeBlob->isBinary()); + $imageBlob = $this->getImageBlob($repository); + $this->assertTrue($imageBlob->isBinary()); } } From a8bfcd173aafc7cc97f6a15bf75370f4bfdc7660 Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Fri, 3 May 2024 09:22:05 +0200 Subject: [PATCH 50/61] Update tests for new git version (#223) --- tests/Gitonomy/Git/Tests/RepositoryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Gitonomy/Git/Tests/RepositoryTest.php b/tests/Gitonomy/Git/Tests/RepositoryTest.php index de433df..fc5c7de 100644 --- a/tests/Gitonomy/Git/Tests/RepositoryTest.php +++ b/tests/Gitonomy/Git/Tests/RepositoryTest.php @@ -43,8 +43,8 @@ public function testGetBlobWithExistingWorks($repository) public function testGetSize($repository) { $size = $repository->getSize(); - $this->assertGreaterThanOrEqual(53, $size, 'Repository is at least 53KB'); - $this->assertLessThan(80, $size, 'Repository is less than 80KB'); + $this->assertGreaterThanOrEqual(57, $size, 'Repository is at least 57KB'); + $this->assertLessThan(84, $size, 'Repository is less than 84KB'); } public function testIsBare() From de32cc09c5f1ac82ad836aefb87e29db3cfb6596 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Fri, 3 May 2024 08:23:26 +0100 Subject: [PATCH 51/61] Set default range counts (#211) * Set default range counts * Force ints --- src/Gitonomy/Git/Parser/DiffParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index e14f879..28f6c18 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -102,9 +102,9 @@ protected function doParse() while ($this->expects('@@ ')) { $vars = $this->consumeRegexp('/-(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?/'); $rangeOldStart = (int) $vars[1]; - $rangeOldCount = (int) $vars[2]; + $rangeOldCount = (int) ($vars[2] ?? 1); $rangeNewStart = (int) $vars[3]; - $rangeNewCount = isset($vars[4]) ? (int) $vars[4] : (int) $vars[2]; // @todo Ici, t'as pris un gros raccourci mon loulou + $rangeNewCount = (int) ($vars[4] ?? 1); $this->consume(' @@'); $this->consumeTo("\n"); $this->consumeNewLine(); From 5a47e03f8f76f40693c8ebbc5ca6a7de48e176a0 Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Mon, 6 May 2024 22:30:56 +0200 Subject: [PATCH 52/61] Add optional entry type option for tree entries (#221) * Add optional entry type option for tree entries * Fix cs problems * Update test for diff range counts * Make each entry type a different function --- src/Gitonomy/Git/Tree.php | 48 ++++++++++++++++++++++++--- tests/Gitonomy/Git/Tests/DiffTest.php | 2 +- tests/Gitonomy/Git/Tests/TreeTest.php | 41 ++++++++++++++++++++++- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/Gitonomy/Git/Tree.php b/src/Gitonomy/Git/Tree.php index 570c8ff..7830cfa 100644 --- a/src/Gitonomy/Git/Tree.php +++ b/src/Gitonomy/Git/Tree.php @@ -24,6 +24,7 @@ class Tree protected $hash; protected $isInitialized = false; protected $entries; + protected $entriesByType; public function __construct(Repository $repository, $hash) { @@ -47,31 +48,68 @@ protected function initialize() $parser->parse($output); $this->entries = []; + $this->entriesByType = [ + 'blob' => [], + 'tree' => [], + 'commit' => [], + ]; foreach ($parser->entries as $entry) { list($mode, $type, $hash, $name) = $entry; if ($type == 'blob') { - $this->entries[$name] = [$mode, $this->repository->getBlob($hash)]; + $treeEntry = [$mode, $this->repository->getBlob($hash)]; } elseif ($type == 'tree') { - $this->entries[$name] = [$mode, $this->repository->getTree($hash)]; + $treeEntry = [$mode, $this->repository->getTree($hash)]; } else { - $this->entries[$name] = [$mode, new CommitReference($hash)]; + $treeEntry = [$mode, new CommitReference($hash)]; } + $this->entries[$name] = $treeEntry; + $this->entriesByType[$type][$name] = $treeEntry; } $this->isInitialized = true; } /** - * @return array An associative array name => $object + * @return array An associative array name => $object */ - public function getEntries() + public function getEntries(): array { $this->initialize(); return $this->entries; } + /** + * @return array An associative array of name => [mode, commit reference] + */ + public function getCommitReferenceEntries(): array + { + $this->initialize(); + + return $this->entriesByType['commit']; + } + + /** + * @return array An associative array of name => [mode, tree] + */ + public function getTreeEntries(): array + { + $this->initialize(); + + return $this->entriesByType['tree']; + } + + /** + * @return array An associative array of name => [mode, blob] + */ + public function getBlobEntries(): array + { + $this->initialize(); + + return $this->entriesByType['blob']; + } + public function getEntry($name) { $this->initialize(); diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index e251d72..2232345 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -139,7 +139,7 @@ public function testDiffRangeParse($repository) $this->assertSame(0, $changes[0]->getRangeOldCount()); $this->assertSame(1, $changes[0]->getRangeNewStart()); - $this->assertSame(0, $changes[0]->getRangeNewCount()); + $this->assertSame(1, $changes[0]->getRangeNewCount()); } /** diff --git a/tests/Gitonomy/Git/Tests/TreeTest.php b/tests/Gitonomy/Git/Tests/TreeTest.php index 4c0476d..b7ba7d3 100644 --- a/tests/Gitonomy/Git/Tests/TreeTest.php +++ b/tests/Gitonomy/Git/Tests/TreeTest.php @@ -13,6 +13,7 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Blob; +use Gitonomy\Git\CommitReference; class TreeTest extends AbstractTest { @@ -21,7 +22,7 @@ class TreeTest extends AbstractTest /** * @dataProvider provideFooBar */ - public function testCase($repository) + public function testGetEntries($repository) { $tree = $repository->getCommit(self::LONGFILE_COMMIT)->getTree(); @@ -34,6 +35,44 @@ public function testCase($repository) $this->assertTrue($entries['README.md'][1] instanceof Blob, 'README.md is a Blob'); } + /** + * @dataProvider provideFooBar + */ + public function testGetCommitReferenceEntries($repository) + { + $tree = $repository->getCommit(self::NO_MESSAGE_COMMIT)->getTree(); + + $commits = $tree->getCommitReferenceEntries(); + + $this->assertNotEmpty($commits['barbaz'], 'barbaz is present'); + $this->assertTrue($commits['barbaz'][1] instanceof CommitReference, 'barbaz is a Commit'); + } + + /** + * @dataProvider provideFooBar + */ + public function testGetTreeEntries($repository) + { + $tree = $repository->getCommit(self::NO_MESSAGE_COMMIT)->getTree(); + + $trees = $tree->getTreeEntries(); + + $this->assertEmpty($trees); + } + + /** + * @dataProvider provideFooBar + */ + public function testGetBlobEntries($repository) + { + $tree = $repository->getCommit(self::NO_MESSAGE_COMMIT)->getTree(); + + $blobs = $tree->getBlobEntries(); + + $this->assertNotEmpty($blobs['README.md'], 'README.md is present'); + $this->assertTrue($blobs['README.md'][1] instanceof Blob, 'README.md is a blob'); + } + /** * @dataProvider provideFooBar */ From 0853cb9f840c2bacd38e2f79c4928e60e1d2b152 Mon Sep 17 00:00:00 2001 From: Claudiu Cristea Date: Tue, 7 May 2024 18:05:13 +0300 Subject: [PATCH 53/61] Edge case: Empty message in the first commit (#217) * Edge case: Empty message in the first commit (#217) Don't try to consume a 2nd new line when the first repository commit has an empty message. * Ensure author identity --- src/Gitonomy/Git/Parser/LogParser.php | 4 +++- tests/Gitonomy/Git/Tests/LogTest.php | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Gitonomy/Git/Parser/LogParser.php b/src/Gitonomy/Git/Parser/LogParser.php index 2672186..4397a46 100644 --- a/src/Gitonomy/Git/Parser/LogParser.php +++ b/src/Gitonomy/Git/Parser/LogParser.php @@ -49,7 +49,9 @@ protected function doParse() $this->consumeGPGSignature(); $this->consumeNewLine(); - $this->consumeNewLine(); + if ($this->cursor < strlen($this->content)) { + $this->consumeNewLine(); + } $message = ''; if ($this->expects(' ')) { diff --git a/tests/Gitonomy/Git/Tests/LogTest.php b/tests/Gitonomy/Git/Tests/LogTest.php index cdf1563..970e55c 100644 --- a/tests/Gitonomy/Git/Tests/LogTest.php +++ b/tests/Gitonomy/Git/Tests/LogTest.php @@ -76,4 +76,19 @@ public function testIterable($repository) } } } + + public function testFirstMessageEmpty() + { + $repository = $this->createEmptyRepository(false); + $repository->run('config', ['--local', 'user.name', '"Unit Test"']); + $repository->run('config', ['--local', 'user.email', '"unit_test@unit-test.com"']); + + // Edge case: first commit lacks a message. + file_put_contents($repository->getWorkingDir().'/file', 'foo'); + $repository->run('add', ['.']); + $repository->run('commit', ['--allow-empty-message', '--no-edit']); + + $commits = $repository->getLog()->getCommits(); + $this->assertCount(1, $commits); + } } From 5fa8b857b9dc61217575190228f66abbe34055ec Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Tue, 21 May 2024 11:10:28 +0200 Subject: [PATCH 54/61] Fix computed data not assinged to cache (#224) Fix assinging two data types to the same variable Fix calling of removed functions that would just return null --- src/Gitonomy/Git/Commit.php | 4 ++-- src/Gitonomy/Git/Parser/CommitParser.php | 4 ++-- src/Gitonomy/Git/Parser/LogParser.php | 8 ++++---- src/Gitonomy/Git/Parser/TagParser.php | 4 ++-- src/Gitonomy/Git/Reference/Tag.php | 4 ++-- src/Gitonomy/Git/ReferenceBag.php | 6 +----- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/Gitonomy/Git/Commit.php b/src/Gitonomy/Git/Commit.php index 2008f7a..005dab3 100644 --- a/src/Gitonomy/Git/Commit.php +++ b/src/Gitonomy/Git/Commit.php @@ -380,9 +380,9 @@ private function getData($name) array_shift($lines); array_shift($lines); - $data['bodyMessage'] = implode("\n", $lines); + $this->data['bodyMessage'] = implode("\n", $lines); - return $data['bodyMessage']; + return $this->data['bodyMessage']; } $parser = new Parser\CommitParser(); diff --git a/src/Gitonomy/Git/Parser/CommitParser.php b/src/Gitonomy/Git/Parser/CommitParser.php index 98234f6..58b9713 100644 --- a/src/Gitonomy/Git/Parser/CommitParser.php +++ b/src/Gitonomy/Git/Parser/CommitParser.php @@ -44,8 +44,8 @@ protected function doParse() $this->consumeNewLine(); $this->consume('committer '); - list($this->committerName, $this->committerEmail, $this->committerDate) = $this->consumeNameEmailDate(); - $this->committerDate = $this->parseDate($this->committerDate); + list($this->committerName, $this->committerEmail, $committerDate) = $this->consumeNameEmailDate(); + $this->committerDate = $this->parseDate($committerDate); // will consume an GPG signed commit if there is one $this->consumeGPGSignature(); diff --git a/src/Gitonomy/Git/Parser/LogParser.php b/src/Gitonomy/Git/Parser/LogParser.php index 4397a46..ad41ce4 100644 --- a/src/Gitonomy/Git/Parser/LogParser.php +++ b/src/Gitonomy/Git/Parser/LogParser.php @@ -37,13 +37,13 @@ protected function doParse() } $this->consume('author '); - list($commit['authorName'], $commit['authorEmail'], $commit['authorDate']) = $this->consumeNameEmailDate(); - $commit['authorDate'] = $this->parseDate($commit['authorDate']); + list($commit['authorName'], $commit['authorEmail'], $authorDate) = $this->consumeNameEmailDate(); + $commit['authorDate'] = $this->parseDate($authorDate); $this->consumeNewLine(); $this->consume('committer '); - list($commit['committerName'], $commit['committerEmail'], $commit['committerDate']) = $this->consumeNameEmailDate(); - $commit['committerDate'] = $this->parseDate($commit['committerDate']); + list($commit['committerName'], $commit['committerEmail'], $committerDate) = $this->consumeNameEmailDate(); + $commit['committerDate'] = $this->parseDate($committerDate); // will consume an GPG signed commit if there is one $this->consumeGPGSignature(); diff --git a/src/Gitonomy/Git/Parser/TagParser.php b/src/Gitonomy/Git/Parser/TagParser.php index 659be18..1a1c084 100644 --- a/src/Gitonomy/Git/Parser/TagParser.php +++ b/src/Gitonomy/Git/Parser/TagParser.php @@ -40,8 +40,8 @@ protected function doParse() $this->consumeNewLine(); $this->consume('tagger '); - list($this->taggerName, $this->taggerEmail, $this->taggerDate) = $this->consumeNameEmailDate(); - $this->taggerDate = $this->parseDate($this->taggerDate); + list($this->taggerName, $this->taggerEmail, $taggerDate) = $this->consumeNameEmailDate(); + $this->taggerDate = $this->parseDate($taggerDate); $this->consumeNewLine(); $this->consumeNewLine(); diff --git a/src/Gitonomy/Git/Reference/Tag.php b/src/Gitonomy/Git/Reference/Tag.php index bca6ca4..78c43b2 100644 --- a/src/Gitonomy/Git/Reference/Tag.php +++ b/src/Gitonomy/Git/Reference/Tag.php @@ -191,9 +191,9 @@ private function getData($name) array_shift($lines); array_pop($lines); - $data['bodyMessage'] = implode("\n", $lines); + $this->data['bodyMessage'] = implode("\n", $lines); - return $data['bodyMessage']; + return $this->data['bodyMessage']; } $parser = new TagParser(); diff --git a/src/Gitonomy/Git/ReferenceBag.php b/src/Gitonomy/Git/ReferenceBag.php index 4b79fc6..adde82c 100644 --- a/src/Gitonomy/Git/ReferenceBag.php +++ b/src/Gitonomy/Git/ReferenceBag.php @@ -354,11 +354,7 @@ protected function initialize() $parser = new Parser\ReferenceParser(); $output = $this->repository->run('show-ref'); } catch (RuntimeException $e) { - $output = $e->getOutput(); - $error = $e->getErrorOutput(); - if ($error) { - throw new RuntimeException('Error while getting list of references: '.$error); - } + $output = null; } $parser->parse($output); From d1c05fdad6c6ae75a7c594daa31a215a9e1e0ce6 Mon Sep 17 00:00:00 2001 From: codebymikey <9484406+codebymikey@users.noreply.github.com> Date: Sun, 3 Nov 2024 15:54:15 +0000 Subject: [PATCH 55/61] Avoid unintentional conversion of index to boolean (#208) Avoid unintentional conversion of index to boolean. --- src/Gitonomy/Git/Parser/DiffParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index 28f6c18..ad22bea 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -92,8 +92,8 @@ protected function doParse() $oldName = $oldName === '/dev/null' ? null : substr($oldName, 2); $newName = $newName === '/dev/null' ? null : substr($newName, 2); - $oldIndex = $oldIndex !== null ?: ''; - $newIndex = $newIndex !== null ?: ''; + $oldIndex = $oldIndex === null ? '' : $oldIndex; + $newIndex = $newIndex === null ? '' : $newIndex; $oldIndex = preg_match('/^0+$/', $oldIndex) ? null : $oldIndex; $newIndex = preg_match('/^0+$/', $newIndex) ? null : $newIndex; $file = new File($oldName, $newName, $oldMode, $newMode, $oldIndex, $newIndex, $isBinary); From ac17834888bf399a4ecae5e108be52c8c5f93958 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 3 Nov 2024 10:59:21 -0500 Subject: [PATCH 56/61] PHP 8.4 support (#225) * PHP 8.4 support * Update tests.yml * Update tests.yml --- .github/workflows/tests.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e40ff9a..4e611ce 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,22 +7,22 @@ on: jobs: tests: - name: Test PHP ${{ matrix.php-version }} ${{ matrix.name }} - runs-on: ubuntu-latest + name: Test PHP ${{ matrix.php }} ${{ matrix.name }} + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - php-version: ['8.1', '8.2', '8.3'] + php: ['8.1', '8.2', '8.3', '8.4'] composer-flags: [''] name: [''] include: - - php: 8.0 + - php: '8.0' composer-flags: '--prefer-lowest' name: '(prefer lowest dependencies)' steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 From 16214e3a57856e685e000b526414926d29990f54 Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Mon, 27 Jan 2025 10:58:38 +0100 Subject: [PATCH 57/61] Fix incorrect file name on new or deleted empty files (#226) * Fix incorrect file name on new or deleted empty files * Add test for empty file diff --- src/Gitonomy/Git/Parser/DiffParser.php | 2 ++ tests/Gitonomy/Git/Tests/DiffTest.php | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index ad22bea..eec47ca 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -38,6 +38,7 @@ protected function doParse() $newMode = $this->consumeTo("\n"); $this->consumeNewLine(); $oldMode = null; + $oldName = '/dev/null'; } if ($this->expects('old mode ')) { $oldMode = $this->consumeTo("\n"); @@ -49,6 +50,7 @@ protected function doParse() if ($this->expects('deleted file mode ')) { $oldMode = $this->consumeTo("\n"); $newMode = null; + $newName = '/dev/null'; $this->consumeNewLine(); } diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index 2232345..c82061b 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -150,4 +150,26 @@ 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()); } + + public function testEmptyNewFile() + { + $diff = Diff::parse("diff --git a/test b/test\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\n"); + $firstFile = $diff->getFiles()[0]; + + $this->assertTrue($firstFile->isCreation()); + $this->assertFalse($firstFile->isDeletion()); + $this->assertSame('test', $firstFile->getNewName()); + $this->assertNull($firstFile->getOldName()); + } + + public function testEmptyOldFile() + { + $diff = Diff::parse("diff --git a/test b/test\ndeleted file mode 100644\nindex e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000\n"); + $firstFile = $diff->getFiles()[0]; + + $this->assertFalse($firstFile->isCreation()); + $this->assertTrue($firstFile->isDeletion()); + $this->assertNull($firstFile->getNewName()); + $this->assertSame('test', $firstFile->getOldName()); + } } From 64d8e79dd4c4cf488dad3a3503f1b0ace0a82759 Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Wed, 29 Jan 2025 14:38:58 +0100 Subject: [PATCH 58/61] fix error with empty index by including raw information in diff (#229) * fix error with empty index by including raw information in diff * fix style error --- src/Gitonomy/Git/Commit.php | 2 +- src/Gitonomy/Git/Diff/File.php | 8 ++ src/Gitonomy/Git/Parser/DiffParser.php | 21 ++++- src/Gitonomy/Git/Repository.php | 2 +- src/Gitonomy/Git/WorkingCopy.php | 4 +- tests/Gitonomy/Git/Tests/DiffTest.php | 109 +++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 6 deletions(-) diff --git a/src/Gitonomy/Git/Commit.php b/src/Gitonomy/Git/Commit.php index 005dab3..573d3b5 100644 --- a/src/Gitonomy/Git/Commit.php +++ b/src/Gitonomy/Git/Commit.php @@ -62,7 +62,7 @@ public function setData(array $data) */ public function getDiff() { - $args = ['-r', '-p', '-m', '-M', '--no-commit-id', '--full-index', $this->revision]; + $args = ['-r', '-p', '--raw', '-m', '-M', '--no-commit-id', '--full-index', $this->revision]; $diff = Diff::parse($this->repository->run('diff-tree', $args)); $diff->setRepository($this->repository); diff --git a/src/Gitonomy/Git/Diff/File.php b/src/Gitonomy/Git/Diff/File.php index d3da24b..bfca155 100644 --- a/src/Gitonomy/Git/Diff/File.php +++ b/src/Gitonomy/Git/Diff/File.php @@ -278,6 +278,10 @@ public function getOldBlob() throw new \LogicException('Can\'t return old Blob on a creation'); } + if ($this->oldIndex === '') { + throw new \RuntimeException('Index is missing to return Blob object.'); + } + return $this->repository->getBlob($this->oldIndex); } @@ -291,6 +295,10 @@ public function getNewBlob() throw new \LogicException('Can\'t return new Blob on a deletion'); } + if ($this->newIndex === '') { + throw new \RuntimeException('Index is missing to return Blob object.'); + } + return $this->repository->getBlob($this->newIndex); } } diff --git a/src/Gitonomy/Git/Parser/DiffParser.php b/src/Gitonomy/Git/Parser/DiffParser.php index eec47ca..15e6c03 100644 --- a/src/Gitonomy/Git/Parser/DiffParser.php +++ b/src/Gitonomy/Git/Parser/DiffParser.php @@ -22,14 +22,31 @@ class DiffParser extends ParserBase protected function doParse() { $this->files = []; + $indexes = []; + // Diff contains raw information + if (str_starts_with($this->content, ':')) { + while ($this->expects(':')) { + $this->consumeRegexp('/\d{6} \d{6} /'); + $oldIndex = $this->consumeShortHash(); + $this->consume(' '); + $newIndex = $this->consumeShortHash(); + $this->consumeTo("\n"); + $this->consumeNewLine(); + $indexes[] = [$oldIndex, $newIndex]; + } + $this->consumeNewLine(); + } elseif (!$this->isFinished()) { + trigger_error('Using Diff::parse without raw information is deprecated. See https://github.com/gitonomy/gitlib/issues/227.', E_USER_DEPRECATED); + } + $fileIndex = 0; while (!$this->isFinished()) { // 1. title $vars = $this->consumeRegexp("/diff --git \"?(a\/.*?)\"? \"?(b\/.*?)\"?\n/"); $oldName = $vars[1]; $newName = $vars[2]; - $oldIndex = null; - $newIndex = null; + $oldIndex = isset($indexes[$fileIndex]) ? $indexes[$fileIndex][0] : null; + $newIndex = isset($indexes[$fileIndex]) ? $indexes[$fileIndex][1] : null; $oldMode = null; $newMode = null; diff --git a/src/Gitonomy/Git/Repository.php b/src/Gitonomy/Git/Repository.php index fe77a88..296496a 100644 --- a/src/Gitonomy/Git/Repository.php +++ b/src/Gitonomy/Git/Repository.php @@ -416,7 +416,7 @@ public function getDiff($revisions) $revisions = new RevisionList($this, $revisions); } - $args = array_merge(['-r', '-p', '-m', '-M', '--no-commit-id', '--full-index'], $revisions->getAsTextArray()); + $args = array_merge(['-r', '-p', '--raw', '-m', '-M', '--no-commit-id', '--full-index'], $revisions->getAsTextArray()); $diff = Diff::parse($this->run('diff', $args)); $diff->setRepository($this); diff --git a/src/Gitonomy/Git/WorkingCopy.php b/src/Gitonomy/Git/WorkingCopy.php index aed3b85..a94fbbb 100644 --- a/src/Gitonomy/Git/WorkingCopy.php +++ b/src/Gitonomy/Git/WorkingCopy.php @@ -50,7 +50,7 @@ public function getUntrackedFiles() public function getDiffPending() { - $diff = Diff::parse($this->run('diff', ['-r', '-p', '-m', '-M', '--full-index'])); + $diff = Diff::parse($this->run('diff', ['-r', '-p', '--raw', '-m', '-M', '--full-index'])); $diff->setRepository($this->repository); return $diff; @@ -58,7 +58,7 @@ public function getDiffPending() public function getDiffStaged() { - $diff = Diff::parse($this->run('diff', ['-r', '-p', '-m', '-M', '--full-index', '--staged'])); + $diff = Diff::parse($this->run('diff', ['-r', '-p', '--raw', '-m', '-M', '--full-index', '--staged'])); $diff->setRepository($this->repository); return $diff; diff --git a/tests/Gitonomy/Git/Tests/DiffTest.php b/tests/Gitonomy/Git/Tests/DiffTest.php index c82061b..e51fc7f 100644 --- a/tests/Gitonomy/Git/Tests/DiffTest.php +++ b/tests/Gitonomy/Git/Tests/DiffTest.php @@ -13,6 +13,8 @@ namespace Gitonomy\Git\Tests; use Gitonomy\Git\Diff\Diff; +use Gitonomy\Git\Diff\File; +use Gitonomy\Git\Repository; class DiffTest extends AbstractTest { @@ -151,6 +153,113 @@ public function testWorksWithUmlauts($repository) $this->assertSame('file_with_umlauts_\303\244\303\266\303\274', $files[0]->getNewName()); } + public function testDeleteFileWithoutRaw() + { + $deprecationCalled = false; + $self = $this; + set_error_handler(function (int $errno, string $errstr) use ($self, &$deprecationCalled): void { + $deprecationCalled = true; + $self->assertSame('Using Diff::parse without raw information is deprecated. See https://github.com/gitonomy/gitlib/issues/227.', $errstr); + }, E_USER_DEPRECATED); + + $diff = Diff::parse(<<<'DIFF' + diff --git a/test b/test + deleted file mode 100644 + index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 + + DIFF); + $firstFile = $diff->getFiles()[0]; + + restore_exception_handler(); + + $this->assertTrue($deprecationCalled); + $this->assertFalse($firstFile->isCreation()); + // TODO: Enable after #226 is merged + //$this->assertTrue($firstFile->isDeletion()); + //$this->assertFalse($firstFile->isChangeMode()); + $this->assertSame('e69de29bb2d1d6434b8b29ae775ad8c2e48c5391', $firstFile->getOldIndex()); + $this->assertNull($firstFile->getNewIndex()); + } + + public function testModeChangeFileWithoutRaw() + { + $deprecationCalled = false; + $self = $this; + set_error_handler(function (int $errno, string $errstr) use ($self, &$deprecationCalled): void { + $deprecationCalled = true; + $self->assertSame('Using Diff::parse without raw information is deprecated. See https://github.com/gitonomy/gitlib/issues/227.', $errstr); + }, E_USER_DEPRECATED); + + $diff = Diff::parse(<<<'DIFF' + diff --git a/a.out b/a.out + old mode 100755 + new mode 100644 + + DIFF); + $firstFile = $diff->getFiles()[0]; + + restore_exception_handler(); + + $this->assertTrue($deprecationCalled); + $this->assertFalse($firstFile->isCreation()); + $this->assertFalse($firstFile->isDeletion()); + $this->assertTrue($firstFile->isChangeMode()); + $this->assertSame('', $firstFile->getOldIndex()); + $this->assertSame('', $firstFile->getNewIndex()); + } + + public function testModeChangeFileWithRaw() + { + $deprecationCalled = false; + set_error_handler(function (int $errno, string $errstr) use (&$deprecationCalled): void { + $deprecationCalled = true; + }, E_USER_DEPRECATED); + + $diff = Diff::parse(<<<'DIFF' + :100755 100644 d1af4b23d0cc9313e5b2d3ef2fb9696c94afaa81 d1af4b23d0cc9313e5b2d3ef2fb9696c94afaa81 M a.out + + diff --git a/a.out b/a.out + old mode 100755 + new mode 100644 + + DIFF); + $firstFile = $diff->getFiles()[0]; + + restore_exception_handler(); + + $this->assertFalse($deprecationCalled); + $this->assertFalse($firstFile->isCreation()); + $this->assertFalse($firstFile->isDeletion()); + $this->assertTrue($firstFile->isChangeMode()); + $this->assertSame('d1af4b23d0cc9313e5b2d3ef2fb9696c94afaa81', $firstFile->getOldIndex()); + $this->assertSame('d1af4b23d0cc9313e5b2d3ef2fb9696c94afaa81', $firstFile->getNewIndex()); + } + + public function testThrowErrorOnBlobGetWithoutIndex() + { + $repository = $this->getMockBuilder(Repository::class)->disableOriginalConstructor()->getMock(); + $file = new File('oldName', 'newName', '100755', '100644', '', '', false); + $file->setRepository($repository); + + try { + $file->getOldBlob(); + } catch(\RuntimeException $exception) { + $this->assertSame('Index is missing to return Blob object.', $exception->getMessage()); + } + + try { + $file->getNewBlob(); + } catch(\RuntimeException $exception) { + $this->assertSame('Index is missing to return Blob object.', $exception->getMessage()); + } + + $this->assertFalse($file->isCreation()); + $this->assertFalse($file->isDeletion()); + $this->assertTrue($file->isChangeMode()); + $this->assertSame('', $file->getOldIndex()); + $this->assertSame('', $file->getNewIndex()); + } + public function testEmptyNewFile() { $diff = Diff::parse("diff --git a/test b/test\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\n"); From de03597af9dcac5d8a024ee33f5a1b77f68547b2 Mon Sep 17 00:00:00 2001 From: Adrian Lorenc <101017881+adrian-lorenc@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:43:33 +0100 Subject: [PATCH 59/61] Consume merge tag (#231) --- src/Gitonomy/Git/Parser/CommitParser.php | 2 ++ src/Gitonomy/Git/Parser/LogParser.php | 2 ++ src/Gitonomy/Git/Parser/ParserBase.php | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/src/Gitonomy/Git/Parser/CommitParser.php b/src/Gitonomy/Git/Parser/CommitParser.php index 58b9713..6fff1ea 100644 --- a/src/Gitonomy/Git/Parser/CommitParser.php +++ b/src/Gitonomy/Git/Parser/CommitParser.php @@ -47,6 +47,8 @@ protected function doParse() list($this->committerName, $this->committerEmail, $committerDate) = $this->consumeNameEmailDate(); $this->committerDate = $this->parseDate($committerDate); + $this->consumeMergeTag(); + // will consume an GPG signed commit if there is one $this->consumeGPGSignature(); diff --git a/src/Gitonomy/Git/Parser/LogParser.php b/src/Gitonomy/Git/Parser/LogParser.php index ad41ce4..53e5b16 100644 --- a/src/Gitonomy/Git/Parser/LogParser.php +++ b/src/Gitonomy/Git/Parser/LogParser.php @@ -45,6 +45,8 @@ protected function doParse() list($commit['committerName'], $commit['committerEmail'], $committerDate) = $this->consumeNameEmailDate(); $commit['committerDate'] = $this->parseDate($committerDate); + $this->consumeMergeTag(); + // will consume an GPG signed commit if there is one $this->consumeGPGSignature(); diff --git a/src/Gitonomy/Git/Parser/ParserBase.php b/src/Gitonomy/Git/Parser/ParserBase.php index 7cd37e7..be149bf 100644 --- a/src/Gitonomy/Git/Parser/ParserBase.php +++ b/src/Gitonomy/Git/Parser/ParserBase.php @@ -136,4 +136,18 @@ protected function consumeGPGSignature() return $this->consumeTo("\n\n"); } + + protected function consumeMergeTag() + { + $expected = "\nmergetag "; + $length = strlen($expected); + $actual = substr($this->content, $this->cursor, $length); + if ($actual != $expected) { + return ''; + } + $this->cursor += $length; + + $this->consumeTo('-----END PGP SIGNATURE-----'); + $this->consume('-----END PGP SIGNATURE-----'); + } } From fae99117474658bd6af131f82d063150a75e6329 Mon Sep 17 00:00:00 2001 From: Ilias Dimopoulos Date: Wed, 4 Jun 2025 17:55:21 +0300 Subject: [PATCH 60/61] Skip third party unsupported headers. (#232) * Skip third party unsupported headers. * Fix sniff remarks. * Sniffs fix v2. --- src/Gitonomy/Git/Parser/LogParser.php | 12 ++++++++ tests/Gitonomy/Git/Tests/LogTest.php | 42 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/Gitonomy/Git/Parser/LogParser.php b/src/Gitonomy/Git/Parser/LogParser.php index 53e5b16..67b8668 100644 --- a/src/Gitonomy/Git/Parser/LogParser.php +++ b/src/Gitonomy/Git/Parser/LogParser.php @@ -51,6 +51,7 @@ protected function doParse() $this->consumeGPGSignature(); $this->consumeNewLine(); + $this->consumeUnsupportedLinesToNewLine(); if ($this->cursor < strlen($this->content)) { $this->consumeNewLine(); } @@ -76,4 +77,15 @@ protected function doParse() $this->log[] = $commit; } } + + protected function consumeUnsupportedLinesToNewLine() + { + // Consume any unsupported lines that may appear in the log output. For + // example, gitbutler headers or other custom metadata but this should + // work regardless of the content. + while (!$this->isFinished() && substr($this->content, $this->cursor, 1) !== "\n") { + $this->consumeTo("\n"); + $this->consumeNewLine(); + } + } } diff --git a/tests/Gitonomy/Git/Tests/LogTest.php b/tests/Gitonomy/Git/Tests/LogTest.php index 970e55c..a02184d 100644 --- a/tests/Gitonomy/Git/Tests/LogTest.php +++ b/tests/Gitonomy/Git/Tests/LogTest.php @@ -12,6 +12,8 @@ namespace Gitonomy\Git\Tests; +use Gitonomy\Git\Parser\LogParser; + class LogTest extends AbstractTest { /** @@ -91,4 +93,44 @@ public function testFirstMessageEmpty() $commits = $repository->getLog()->getCommits(); $this->assertCount(1, $commits); } + + public function testParsesCommitsWithAndWithoutGitButlerHeaders(): void + { + $logContent = <<<'EOT' + commit 1111111111111111111111111111111111111111 + tree abcdefabcdefabcdefabcdefabcdefabcdefabcd + author John Doe 1620000000 +0000 + committer John Doe 1620000000 +0000 + + First commit message + + commit 2222222222222222222222222222222222222222 + tree abcdefabcdefabcdefabcdefabcdefabcdefabcd + parent 1111111111111111111111111111111111111111 + author Jane Smith 1620003600 +0000 + committer Jane Smith 1620003600 +0000 + gitbutler-headers-version: 2 + gitbutler-change-id: a7bd485c-bae6-45b2-910f-163c78aace81 + + Commit with GitButler headers + + commit 3333333333333333333333333333333333333333 + tree abcdefabcdefabcdefabcdefabcdefabcdefabcd + author John Doe 1620007200 +0000 + committer Jane Smith 1620007200 +0000 + + Another commit without GitButler headers + + EOT; + + $parser = new LogParser(); + $parser->parse($logContent); + + $log = $parser->log; + $this->assertCount(3, $log); + + $this->assertEquals("First commit message\n", $log[0]['message']); + $this->assertEquals("Commit with GitButler headers\n", $log[1]['message']); + $this->assertEquals("Another commit without GitButler headers\n", $log[2]['message']); + } } From e6e9da54bf035f4637322c97ef02cd0de0e91454 Mon Sep 17 00:00:00 2001 From: Patrick-Beuks Date: Thu, 26 Jun 2025 16:46:39 +0200 Subject: [PATCH 61/61] Fix null passed to strlen in parsers (#234) When a command is run and fails it returns null. This is then passed to the parser and it handles it as an empty string Since PHP 8.0 it is deprecated to pass null to `strlen` so instead make this an empty String. --- src/Gitonomy/Git/Parser/ParserBase.php | 2 +- src/Gitonomy/Git/ReferenceBag.php | 2 +- tests/Gitonomy/Git/Tests/ReferenceBagTest.php | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Gitonomy/Git/Parser/ParserBase.php b/src/Gitonomy/Git/Parser/ParserBase.php index be149bf..45a8002 100644 --- a/src/Gitonomy/Git/Parser/ParserBase.php +++ b/src/Gitonomy/Git/Parser/ParserBase.php @@ -25,7 +25,7 @@ abstract protected function doParse(); public function parse($content) { $this->cursor = 0; - $this->content = $content; + $this->content = $content ?? ''; $this->length = strlen($this->content); $this->doParse(); diff --git a/src/Gitonomy/Git/ReferenceBag.php b/src/Gitonomy/Git/ReferenceBag.php index adde82c..71ef9ae 100644 --- a/src/Gitonomy/Git/ReferenceBag.php +++ b/src/Gitonomy/Git/ReferenceBag.php @@ -354,7 +354,7 @@ protected function initialize() $parser = new Parser\ReferenceParser(); $output = $this->repository->run('show-ref'); } catch (RuntimeException $e) { - $output = null; + return; } $parser->parse($output); diff --git a/tests/Gitonomy/Git/Tests/ReferenceBagTest.php b/tests/Gitonomy/Git/Tests/ReferenceBagTest.php index 35756bf..f9b9c82 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceBagTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceBagTest.php @@ -44,4 +44,13 @@ public function testUnknownReference(Repository $repository) $this->assertArrayNotHasKey('refs/pull/1/head', $refs); $this->assertArrayNotHasKey('refs/notes/gtm-data', $refs); } + + /** + * @dataProvider provideEmpty + */ + public function testEmptyRepo(Repository $repository) + { + $refs = $repository->getReferences()->getAll(); + $this->assertSame([], $refs); + } }