99% of 747OPs |
95% of 179Lines |
76% of 78Branches |
100% of 39Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum\scripts\git; |
4 |
|
5 |
use |
6 |
mageekguy\atoum, |
7 |
mageekguy\atoum\script, |
8 |
mageekguy\atoum\scripts, |
9 |
mageekguy\atoum\exceptions, |
10 |
mageekguy\atoum\cli\commands |
11 |
; |
12 |
|
13 |
class pusher extends script\configurable |
14 |
{ |
15 |
const defaultRemote = 'origin'; |
16 |
const defaultTagFile = '.tag'; |
17 |
const versionPattern = '$Rev: %s $'; |
18 |
const majorVersion = 1; |
19 |
const minorVersion = 2; |
20 |
const patchVersion = 3; |
21 |
|
22 |
protected $remote = ''; |
23 |
protected $tagFile = null; |
24 |
protected $workingDirectory = ''; |
25 |
protected $taggerEngine = null; |
26 |
protected $git = null; |
27 |
protected $tagMajorVersion = false; |
28 |
protected $tagMinorVersion = false; |
29 |
|
30 |
public function __construct($name, atoum\adapter $adapter = null)100% |
31 |
{ |
32 |
parent::__construct($name, $adapter); |
33 |
|
34 |
$this |
35 |
->setRemote() |
36 |
->setTagFile() |
37 |
->setTaggerEngine() |
38 |
->setWorkingDirectory() |
39 |
->setGit() |
40 |
; |
41 |
} |
42 |
|
43 |
public function setRemote($remote = null)100% |
44 |
{ |
45 |
$this->remote = $remote ?: self::defaultRemote; |
46 |
|
47 |
return $this; |
48 |
} |
49 |
|
50 |
public function getRemote()100% |
51 |
{ |
52 |
return $this->remote; |
53 |
} |
54 |
|
55 |
public function setTagFile($tagFile = null)100% |
56 |
{ |
57 |
if ($tagFile !== null) |
58 |
{ |
59 |
$tagFile = (string) $tagFile; |
60 |
} |
61 |
else |
62 |
{ |
63 |
$tagFile = $this->getDirectory() . self::defaultTagFile; |
64 |
} |
65 |
|
66 |
$this->tagFile = $tagFile; |
67 |
|
68 |
return $this; |
69 |
} |
70 |
|
71 |
public function getTagFile()100% |
72 |
{ |
73 |
return $this->tagFile; |
74 |
} |
75 |
|
76 |
public function setTaggerEngine(scripts\tagger\engine $engine = null)100% |
77 |
{ |
78 |
$this->taggerEngine = $engine ?: new scripts\tagger\engine(); |
79 |
|
80 |
return $this; |
81 |
} |
82 |
|
83 |
public function getTaggerEngine()100% |
84 |
{ |
85 |
return $this->taggerEngine; |
86 |
} |
87 |
|
88 |
public function setWorkingDirectory($workingDirectory = null)100% |
89 |
{ |
90 |
$this->workingDirectory = $workingDirectory ?: $this->adapter->getcwd(); |
91 | |
92 |
return $this; |
93 |
} |
94 |
|
95 |
public function getWorkingDirectory()100% |
96 |
{ |
97 |
return $this->workingDirectory; |
98 |
} |
99 |
|
100 |
public function setGit(commands\git $git = null)100% |
101 |
{ |
102 |
$this->git = $git ?: new commands\git(); |
103 |
|
104 |
return $this; |
105 |
} |
106 |
|
107 |
public function getGit()100% |
108 |
{ |
109 |
return $this->git; |
110 |
} |
111 |
|
112 |
public function tagMajorVersion()100% |
113 |
{ |
114 |
$this->tagMajorVersion = true; |
115 |
$this->tagMinorVersion = false; |
116 |
} |
117 |
|
118 |
public function tagMinorVersion()100% |
119 |
{ |
120 |
$this->tagMajorVersion = false; |
121 |
$this->tagMinorVersion = true; |
122 |
} |
123 |
|
124 |
|
125 |
public function tagPatchVersion()100% |
126 |
{ |
127 |
$this->tagMajorVersion = false; |
128 |
$this->tagMinorVersion = false; |
129 |
} |
130 |
|
131 |
protected function setArgumentHandlers()81% |
132 |
{ |
133 |
parent::setArgumentHandlers() |
134 |
->addArgumentHandler( |
135 |
function($script, $argument, $remote) { |
136 |
if (sizeof($remote) != 1) |
137 |
{ |
138 |
throw new exceptions\logic\invalidArgument(sprintf($script->getLocale()->_('Bad usage of %s, do php %s --help for more informations'), $remote, $script->getName())); |
139 |
} |
140 |
|
141 |
$script->setRemote(reset($remote)); |
142 |
}, |
143 |
array('-tr', '--to-remote'), |
144 |
'<string>', |
145 |
$this->locale->_('<string> will be used as remote') |
146 |
) |
147 |
->addArgumentHandler( |
148 |
function($script, $argument, $tagFile) { |
149 |
if (sizeof($tagFile) != 1) |
150 |
{ |
151 |
throw new exceptions\logic\invalidArgument(sprintf($script->getLocale()->_('Bad usage of %s, do php %s --help for more informations'), $argument, $script->getName())); |
152 |
} |
153 |
|
154 |
$script->setTagFile(reset($tagFile)); |
155 |
}, |
156 |
array('-tf', '--tag-file'), |
157 |
'<path>', |
158 |
$this->locale->_('File <path> will be used to store last tag') |
159 |
) |
160 |
->addArgumentHandler( |
161 |
function($script, $argument, $value) { |
162 |
$script->tagMajorVersion(); |
163 |
}, |
164 |
array('-MR', '--major-release'), |
165 |
null, |
166 |
$this->locale->_('Tag a new major version') |
167 |
) |
168 |
->addArgumentHandler( |
169 |
function($script, $argument, $value) { |
170 |
$script->tagMinorVersion(); |
171 |
}, |
172 |
array('-mr', '--minor-release'), |
173 |
null, |
174 |
$this->locale->_('Tag a new minor version') |
175 |
) |
176 |
->addArgumentHandler( |
177 |
function($script, $argument, $value) { |
178 |
$script->tagPatchVersion(); |
179 |
}, |
180 |
array('-pr', '--patch-release'), |
181 |
null, |
182 |
$this->locale->_('Tag a new patch version') |
183 |
) |
184 |
; |
185 |
|
186 |
return $this; |
187 |
} |
188 |
|
189 |
protected function doRun()100% |
190 |
{ |
191 |
try |
192 |
{ |
193 |
$tag = @file_get_contents($this->tagFile); |
194 |
|
195 |
if ($tag === false) |
196 |
{ |
197 |
throw new exceptions\runtime('Unable to read \'' . $this->tagFile . '\''); |
198 |
} |
199 |
|
200 |
$tag = $this->getNextVersion(trim($tag)); |
201 |
|
202 |
if (@file_put_contents($this->tagFile, $tag) === false) |
203 |
{ |
204 |
throw new exceptions\runtime('Unable to write in \'' . $this->tagFile . '\''); |
205 |
} |
206 |
|
207 |
$this->taggerEngine->setSrcDirectory($this->workingDirectory); |
208 |
|
209 |
if ($this->tagStableVersion($tag) === true) |
210 |
{ |
211 |
if ($this->createGitTag($tag) === true) |
212 |
{ |
213 |
if ($this->tagDevelopmentVersion('DEVELOPMENT-' . $tag) === true) |
214 |
{ |
215 |
if ($this->pushToRemote($tag) === true) |
216 |
{ |
217 |
if ($this->pushTagToRemote($tag) === true) |
218 |
{ |
219 |
$this->writeInfo('Tag \'' . $tag . '\' successfully sent to remote \'' . $this->remote . '\''); |
220 |
} |
221 |
} |
222 |
} |
223 |
} |
224 |
} |
225 |
|
226 |
} |
227 |
catch (\exception $exception) |
228 |
{ |
229 |
$this->writeError($exception->getMessage()); |
230 |
} |
231 |
|
232 |
return $this; |
233 |
} |
234 |
|
235 |
protected function getNextVersion($tag)100% |
236 |
{ |
237 |
$versionPattern = '/^(\d+)\.(\d+)\.(\d+)$/'; |
238 |
$increment = function($position) { |
239 |
return function($matches) use ($position) { |
240 |
for ($i = 1; $i <= 3; $i++) |
241 |
{ |
242 |
if ($i > $position) |
243 |
{ |
244 |
$matches[$i] = 0; |
245 |
} |
246 |
|
247 |
if ($i === $position) |
248 |
{ |
249 |
$matches[$i] += 1; |
250 |
} |
251 |
} |
252 |
|
253 |
return implode('.', array_slice($matches, 1)); |
254 |
}; |
255 |
}; |
256 |
|
257 |
if ($this->tagMajorVersion === true) |
258 |
{ |
259 |
return preg_replace_callback($versionPattern, $increment(self::majorVersion), $tag); |
260 |
} |
261 |
|
262 |
if ($this->tagMinorVersion === true) |
263 |
{ |
264 |
return preg_replace_callback($versionPattern, $increment(self::minorVersion), $tag); |
265 |
} |
266 |
|
267 |
return preg_replace_callback($versionPattern, $increment(self::patchVersion), $tag); |
268 |
} |
269 |
|
270 |
private function tagSrcWith($tag)100% |
271 |
{ |
272 |
$this->taggerEngine |
273 |
->setVersion(sprintf(static::versionPattern, $tag)) |
274 |
->tagVersion() |
275 |
; |
276 |
|
277 |
return $this; |
278 |
} |
279 |
|
280 |
private function tagStableVersion($tag)100% |
281 |
{ |
282 |
$this->tagSrcWith($tag); |
283 |
|
284 |
try |
285 |
{ |
286 |
$this->git->addAllAndCommit('Set version to ' . $tag . '.'); |
287 |
} |
288 |
catch (\exception $exception) |
289 |
{ |
290 |
$this->writeError($exception->getMessage()); |
291 |
|
292 |
$this->git->checkoutAllFiles(); |
293 |
|
294 |
return false; |
295 |
} |
296 |
|
297 |
return true; |
298 |
} |
299 |
|
300 |
private function createGitTag($tag)100% |
301 |
{ |
302 |
try |
303 |
{ |
304 |
$this->git->createTag($tag); |
305 |
} |
306 |
catch (\exception $exception) |
307 |
{ |
308 |
$this->writeError($exception->getMessage()); |
309 |
|
310 |
$this->git->resetHardTo('HEAD~1'); |
311 |
|
312 |
return false; |
313 |
} |
314 |
|
315 |
return true; |
316 |
} |
317 |
|
318 |
private function tagDevelopmentVersion($tag)100% |
319 |
{ |
320 |
$this->tagSrcWith($tag); |
321 |
|
322 |
try |
323 |
{ |
324 |
$this->git->addAllAndCommit('Set version to ' . $tag . '.'); |
325 |
} |
326 |
catch (\exception $exception) |
327 |
{ |
328 |
$this->writeError($exception->getMessage()); |
329 |
|
330 |
$this->git->resetHardTo('HEAD~1'); |
331 |
|
332 |
return false; |
333 |
} |
334 |
|
335 |
return true; |
336 |
} |
337 |
|
338 |
private function pushToRemote($tag)100% |
339 |
{ |
340 |
try |
341 |
{ |
342 |
$this->git->push($this->remote); |
343 |
} |
344 |
catch (\exception $exception) |
345 |
{ |
346 |
$this->writeError($exception->getMessage()); |
347 |
|
348 |
$this->git |
349 |
->deleteLocalTag($tag) |
350 |
->resetHardTo('HEAD~2') |
351 |
; |
352 |
|
353 |
return false; |
354 |
} |
355 |
|
356 |
return true; |
357 |
} |
358 |
|
359 |
private function pushTagToRemote($tag)100% |
360 |
{ |
361 |
try |
362 |
{ |
363 |
$this->git->pushTag($tag, $this->remote); |
364 |
} |
365 |
catch (\exception $exception) |
366 |
{ |
367 |
$this->writeError($exception->getMessage()); |
368 |
|
369 |
$this->git |
370 |
->deleteLocalTag($tag) |
371 |
->resetHardTo('HEAD~2') |
372 |
->forcePush($this->remote) |
373 |
; |
374 |
|
375 |
return false; |
376 |
} |
377 |
|
378 |
return true; |
379 |
} |
380 |
} |