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 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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