Skip to content

Commit cff9b15

Browse files
borgoatGrahamCampbell
authored andcommitted
Data in annotated tags (#115)
* improved Tag with TagParser unit test for annotated tags * use gitonomy/foobar as annotated tag was added there
1 parent 1b9f3eb commit cff9b15

File tree

3 files changed

+261
-0
lines changed

3 files changed

+261
-0
lines changed

src/Gitonomy/Git/Parser/TagParser.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Gitonomy.
5+
*
6+
* (c) Alexandre Salomé <alexandre.salome@gmail.com>
7+
* (c) Julien DIDIER <genzo.wm@gmail.com>
8+
*
9+
* This source file is subject to the MIT license that is bundled
10+
* with this source code in the file LICENSE.
11+
*/
12+
namespace Gitonomy\Git\Parser;
13+
14+
use Gitonomy\Git\Exception\RuntimeException;
15+
16+
class TagParser extends ParserBase
17+
{
18+
public $object;
19+
public $type;
20+
public $tag;
21+
public $taggerName;
22+
public $taggerEmail;
23+
public $taggerDate;
24+
public $gpgSignature;
25+
public $message;
26+
27+
protected function doParse()
28+
{
29+
$this->consume('object ');
30+
$this->object = $this->consumeHash();
31+
$this->consumeNewLine();
32+
33+
$this->consume('type ');
34+
$this->type = $this->consumeTo("\n");
35+
$this->consumeNewLine();
36+
37+
$this->consume('tag ');
38+
$this->tag = $this->consumeTo("\n");
39+
$this->consumeNewLine();
40+
41+
$this->consume('tagger ');
42+
list($this->taggerName, $this->taggerEmail, $this->taggerDate) = $this->consumeNameEmailDate();
43+
$this->taggerDate = $this->parseDate($this->taggerDate);
44+
45+
$this->consumeNewLine();
46+
$this->consumeNewLine();
47+
48+
try {
49+
$this->message = $this->consumeTo("-----BEGIN PGP SIGNATURE-----");
50+
$this->gpgSignature = $this->consumeGPGSignature();
51+
} catch (RuntimeException $e) {
52+
$this->message = $this->consumeAll();
53+
}
54+
}
55+
56+
protected function consumeGPGSignature()
57+
{
58+
$expected = "-----BEGIN PGP SIGNATURE-----";
59+
$length = strlen($expected);
60+
$actual = substr($this->content, $this->cursor, $length);
61+
if ($actual != $expected) {
62+
return '';
63+
}
64+
$this->cursor += $length;
65+
66+
return $this->consumeTo("-----END PGP SIGNATURE-----");
67+
}
68+
69+
protected function consumeNameEmailDate()
70+
{
71+
if (!preg_match('/(([^\n]*) <([^\n]*)> (\d+ [+-]\d{4}))/A', $this->content, $vars, 0, $this->cursor)) {
72+
throw new RuntimeException('Unable to parse name, email and date');
73+
}
74+
75+
$this->cursor += strlen($vars[1]);
76+
77+
return array($vars[2], $vars[3], $vars[4]);
78+
}
79+
80+
protected function parseDate($text)
81+
{
82+
$date = \DateTime::createFromFormat('U e O', $text.' UTC');
83+
84+
if (!$date instanceof \DateTime) {
85+
throw new RuntimeException(sprintf('Unable to convert "%s" to datetime', $text));
86+
}
87+
88+
return $date;
89+
}
90+
}

src/Gitonomy/Git/Reference/Tag.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
namespace Gitonomy\Git\Reference;
1414

1515
use Gitonomy\Git\Exception\RuntimeException;
16+
use Gitonomy\Git\Exception\ProcessException;
1617
use Gitonomy\Git\Reference;
18+
use Gitonomy\Git\Parser\TagParser;
1719

1820
/**
1921
* Representation of a tag reference.
@@ -30,4 +32,153 @@ public function getName()
3032

3133
return $vars[1];
3234
}
35+
36+
/**
37+
* Check if tag is annotated.
38+
*
39+
* @return bool
40+
*/
41+
public function isAnnotated()
42+
{
43+
try {
44+
$this->repository->run('cat-file', array('tag', $this->revision));
45+
} catch (ProcessException $e) {
46+
return false; // Is not an annotated tag
47+
}
48+
49+
return true;
50+
}
51+
52+
/**
53+
* Returns the tagger name.
54+
*
55+
* @return string A name
56+
*/
57+
public function getTaggerName()
58+
{
59+
return $this->getData('taggerName');
60+
}
61+
62+
/**
63+
* Returns the comitter email.
64+
*
65+
* @return string An email
66+
*/
67+
public function getTaggerEmail()
68+
{
69+
return $this->getData('taggerEmail');
70+
}
71+
72+
/**
73+
* Returns the authoring date.
74+
*
75+
* @return DateTime A time object
76+
*/
77+
public function getTaggerDate()
78+
{
79+
return $this->getData('taggerDate');
80+
}
81+
82+
/**
83+
* Returns the message of the commit.
84+
*
85+
* @return string A tag message
86+
*/
87+
public function getMessage()
88+
{
89+
return $this->getData('message');
90+
}
91+
92+
/**
93+
* Returns the subject message (the first line).
94+
*
95+
* @return string The subject message
96+
*/
97+
public function getSubjectMessage()
98+
{
99+
return $this->getData('subjectMessage');
100+
}
101+
102+
/**
103+
* Return the body message.
104+
*
105+
* @return string The body message
106+
*/
107+
public function getBodyMessage()
108+
{
109+
return $this->getData('bodyMessage');
110+
}
111+
112+
/**
113+
* Return the GPG signature.
114+
*
115+
* @return string The GPG signature
116+
*/
117+
public function getGPGSignature()
118+
{
119+
return $this->getData('gpgSignature');
120+
}
121+
122+
/**
123+
* Check whether tag is signed.
124+
*
125+
* @return boolean
126+
*/
127+
public function isSigned()
128+
{
129+
try {
130+
$this->getGPGSignature();
131+
return true;
132+
} catch (\InvalidArgumentException $e) {
133+
return false;
134+
}
135+
}
136+
137+
private function getData($name)
138+
{
139+
if (!$this->isAnnotated()) {
140+
return false;
141+
}
142+
143+
if (isset($this->data[$name])) {
144+
return $this->data[$name];
145+
}
146+
147+
if ($name === 'subjectMessage') {
148+
$lines = explode("\n", $this->getData('message'));
149+
$this->data['subjectMessage'] = reset($lines);
150+
151+
return $this->data['subjectMessage'];
152+
}
153+
154+
if ($name === 'bodyMessage') {
155+
$message = $this->getData('message');
156+
157+
$lines = explode("\n", $message);
158+
159+
array_shift($lines);
160+
array_pop($lines);
161+
162+
$data['bodyMessage'] = implode("\n", $lines);
163+
164+
return $data['bodyMessage'];
165+
}
166+
167+
$parser = new TagParser();
168+
$result = $this->repository->run('cat-file', array('tag', $this->revision));
169+
170+
$parser->parse($result);
171+
172+
$this->data['taggerName'] = $parser->taggerName;
173+
$this->data['taggerEmail'] = $parser->taggerEmail;
174+
$this->data['taggerDate'] = $parser->taggerDate;
175+
$this->data['message'] = $parser->message;
176+
$this->data['gpgSignature'] = $parser->gpgSignature;
177+
178+
if (!isset($this->data[$name])) {
179+
throw new \InvalidArgumentException(sprintf('No data named "%s" in Tag.', $name));
180+
}
181+
182+
return $this->data[$name];
183+
}
33184
}

tests/Gitonomy/Git/Tests/ReferenceTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,31 @@ public function testGetTag($repository)
7474
$tag = $repository->getReferences()->getTag('0.1');
7575

7676
$this->assertTrue($tag instanceof Tag, 'Tag object is correct type');
77+
$this->assertFalse($tag->isAnnotated(), 'Tag is not annotated');
7778

7879
$this->assertEquals(self::LONGFILE_COMMIT, $tag->getCommitHash(), 'Commit hash is correct');
7980
$this->assertEquals(self::LONGFILE_COMMIT, $tag->getCommit()->getHash(), 'Commit hash is correct');
8081
}
8182

83+
/**
84+
* @dataProvider provideFoobar
85+
*/
86+
public function testAnnotatedTag($repository)
87+
{
88+
$tag = $repository->getReferences()->getTag('annotated');
89+
90+
$this->assertTrue($tag instanceof Tag, 'Tag object is correct type');
91+
$this->assertTrue($tag->isAnnotated(), 'Tag is annotated');
92+
$this->assertFalse($tag->isSigned(), 'Tag is not signed');
93+
94+
$this->assertEquals('Graham Campbell', $tag->getTaggerName(), 'Tagger name is correct');
95+
$this->assertEquals('graham@alt-three.com', $tag->getTaggerEmail(), 'Tagger email is correct');
96+
$this->assertEquals(1471428000, $tag->getTaggerDate()->getTimestamp(), 'Tag date is correct');
97+
98+
$this->assertEquals('heading', $tag->getSubjectMessage(), 'Message heading is correct');
99+
$this->assertEquals("body\nbody", $tag->getBodyMessage(), 'Message body is correct');
100+
}
101+
82102
/**
83103
* @dataProvider provideFoobar
84104
* @expectedException Gitonomy\Git\Exception\ReferenceNotFoundException

0 commit comments

Comments
 (0)