/classes/scripts/git/pusher.php

https://github.com/agallou/atoum · PHP · 380 lines · 312 code · 68 blank · 0 comment · 17 complexity · 81deed315688dc09ff2cdd722fdccbd7 MD5 · raw file

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