GitDownloaderTest.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Test\Downloader;
  12. use Composer\Downloader\GitDownloader;
  13. use Composer\Config;
  14. use Composer\TestCase;
  15. use Composer\Util\Filesystem;
  16. use Composer\Util\Platform;
  17. class GitDownloaderTest extends TestCase
  18. {
  19. /** @var Filesystem */
  20. private $fs;
  21. /** @var string */
  22. private $workingDir;
  23. protected function setUp()
  24. {
  25. $this->fs = new Filesystem;
  26. $this->workingDir = $this->getUniqueTmpDirectory();
  27. }
  28. protected function tearDown()
  29. {
  30. if (is_dir($this->workingDir)) {
  31. $this->fs->removeDirectory($this->workingDir);
  32. }
  33. }
  34. protected function setupConfig($config = null) {
  35. if (!$config) {
  36. $config = new Config();
  37. }
  38. if (!$config->has('home')) {
  39. $tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'cmptest-'.md5(uniqid('', true));
  40. $config->merge(array('config' => array('home' => $tmpDir)));
  41. }
  42. return $config;
  43. }
  44. protected function getDownloaderMock($io = null, $config = null, $executor = null, $filesystem = null)
  45. {
  46. $io = $io ?: $this->getMock('Composer\IO\IOInterface');
  47. $executor = $executor ?: $this->getMock('Composer\Util\ProcessExecutor');
  48. $filesystem = $filesystem ?: $this->getMock('Composer\Util\Filesystem');
  49. $config = $this->setupConfig($config);
  50. return new GitDownloader($io, $config, $executor, $filesystem);
  51. }
  52. /**
  53. * @expectedException \InvalidArgumentException
  54. */
  55. public function testDownloadForPackageWithoutSourceReference()
  56. {
  57. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  58. $packageMock->expects($this->once())
  59. ->method('getSourceReference')
  60. ->will($this->returnValue(null));
  61. $downloader = $this->getDownloaderMock();
  62. $downloader->download($packageMock, '/path');
  63. }
  64. public function testDownload()
  65. {
  66. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  67. $packageMock->expects($this->any())
  68. ->method('getSourceReference')
  69. ->will($this->returnValue('1234567890123456789012345678901234567890'));
  70. $packageMock->expects($this->any())
  71. ->method('getSourceUrls')
  72. ->will($this->returnValue(array('https://example.com/composer/composer')));
  73. $packageMock->expects($this->any())
  74. ->method('getSourceUrl')
  75. ->will($this->returnValue('https://example.com/composer/composer'));
  76. $packageMock->expects($this->any())
  77. ->method('getPrettyVersion')
  78. ->will($this->returnValue('dev-master'));
  79. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  80. $processExecutor->expects($this->at(0))
  81. ->method('execute')
  82. ->with($this->equalTo($this->winCompat('git --version')))
  83. ->will($this->returnCallback(function($command, &$output = null) {
  84. $output = 'git version 1.0.0';
  85. return 0;
  86. }));
  87. $expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer");
  88. $processExecutor->expects($this->at(1))
  89. ->method('execute')
  90. ->with($this->equalTo($expectedGitCommand))
  91. ->will($this->returnValue(0));
  92. $processExecutor->expects($this->at(2))
  93. ->method('execute')
  94. ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  95. ->will($this->returnValue(0));
  96. $processExecutor->expects($this->at(3))
  97. ->method('execute')
  98. ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  99. ->will($this->returnValue(0));
  100. $processExecutor->expects($this->at(4))
  101. ->method('execute')
  102. ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  103. ->will($this->returnValue(0));
  104. $downloader = $this->getDownloaderMock(null, null, $processExecutor);
  105. $downloader->download($packageMock, 'composerPath');
  106. }
  107. public function testDownloadWithCache()
  108. {
  109. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  110. $packageMock->expects($this->any())
  111. ->method('getSourceReference')
  112. ->will($this->returnValue('1234567890123456789012345678901234567890'));
  113. $packageMock->expects($this->any())
  114. ->method('getSourceUrls')
  115. ->will($this->returnValue(array('https://example.com/composer/composer')));
  116. $packageMock->expects($this->any())
  117. ->method('getSourceUrl')
  118. ->will($this->returnValue('https://example.com/composer/composer'));
  119. $packageMock->expects($this->any())
  120. ->method('getPrettyVersion')
  121. ->will($this->returnValue('dev-master'));
  122. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  123. $processExecutor->expects($this->at(0))
  124. ->method('execute')
  125. ->with($this->equalTo($this->winCompat('git --version')))
  126. ->will($this->returnCallback(function($command, &$output = null) {
  127. $output = 'git version 2.3.1';
  128. return 0;
  129. }));
  130. $config = new Config;
  131. $this->setupConfig($config);
  132. $cachePath = $config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', 'https://example.com/composer/composer').'/';
  133. $expectedGitCommand = $this->winCompat(sprintf("git clone --mirror 'https://example.com/composer/composer' '%s'", $cachePath));
  134. $processExecutor->expects($this->at(1))
  135. ->method('execute')
  136. ->with($this->equalTo($expectedGitCommand))
  137. ->will($this->returnValue(0));
  138. $expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' --dissociate --reference '%s' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer", $cachePath));
  139. $processExecutor->expects($this->at(2))
  140. ->method('execute')
  141. ->with($this->equalTo($expectedGitCommand))
  142. ->will($this->returnValue(0));
  143. $processExecutor->expects($this->at(3))
  144. ->method('execute')
  145. ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  146. ->will($this->returnValue(0));
  147. $processExecutor->expects($this->at(4))
  148. ->method('execute')
  149. ->with($this->equalTo($this->winCompat("git checkout 'master' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  150. ->will($this->returnValue(0));
  151. $processExecutor->expects($this->at(5))
  152. ->method('execute')
  153. ->with($this->equalTo($this->winCompat("git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  154. ->will($this->returnValue(0));
  155. $downloader = $this->getDownloaderMock(null, $config, $processExecutor);
  156. $downloader->download($packageMock, 'composerPath');
  157. }
  158. public function testDownloadUsesVariousProtocolsAndSetsPushUrlForGithub()
  159. {
  160. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  161. $packageMock->expects($this->any())
  162. ->method('getSourceReference')
  163. ->will($this->returnValue('ref'));
  164. $packageMock->expects($this->any())
  165. ->method('getSourceUrls')
  166. ->will($this->returnValue(array('https://github.com/mirrors/composer', 'https://github.com/composer/composer')));
  167. $packageMock->expects($this->any())
  168. ->method('getSourceUrl')
  169. ->will($this->returnValue('https://github.com/composer/composer'));
  170. $packageMock->expects($this->any())
  171. ->method('getPrettyVersion')
  172. ->will($this->returnValue('1.0.0'));
  173. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  174. $processExecutor->expects($this->at(0))
  175. ->method('execute')
  176. ->with($this->equalTo($this->winCompat('git --version')))
  177. ->will($this->returnCallback(function($command, &$output = null) {
  178. $output = 'git version 1.0.0';
  179. return 0;
  180. }));
  181. $expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://github.com/mirrors/composer' && git fetch composer");
  182. $processExecutor->expects($this->at(1))
  183. ->method('execute')
  184. ->with($this->equalTo($expectedGitCommand))
  185. ->will($this->returnValue(1));
  186. $processExecutor->expects($this->at(2))
  187. ->method('getErrorOutput')
  188. ->with()
  189. ->will($this->returnValue('Error1'));
  190. $expectedGitCommand = $this->winCompat("git clone --no-checkout 'git@github.com:mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'git@github.com:mirrors/composer' && git fetch composer");
  191. $processExecutor->expects($this->at(3))
  192. ->method('execute')
  193. ->with($this->equalTo($expectedGitCommand))
  194. ->will($this->returnValue(0));
  195. $expectedGitCommand = $this->winCompat("git remote set-url origin 'https://github.com/composer/composer'");
  196. $processExecutor->expects($this->at(4))
  197. ->method('execute')
  198. ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  199. ->will($this->returnValue(0));
  200. $expectedGitCommand = $this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'");
  201. $processExecutor->expects($this->at(5))
  202. ->method('execute')
  203. ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  204. ->will($this->returnValue(0));
  205. $processExecutor->expects($this->at(6))
  206. ->method('execute')
  207. ->with($this->equalTo('git branch -r'))
  208. ->will($this->returnValue(0));
  209. $processExecutor->expects($this->at(7))
  210. ->method('execute')
  211. ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  212. ->will($this->returnValue(0));
  213. $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
  214. $downloader->download($packageMock, 'composerPath');
  215. }
  216. public function pushUrlProvider()
  217. {
  218. return array(
  219. // ssh proto should use git@ all along
  220. array(array('ssh'), 'git@github.com:composer/composer', 'git@github.com:composer/composer.git'),
  221. // auto-proto uses git@ by default for push url, but not fetch
  222. array(array('https', 'ssh', 'git'), 'https://github.com/composer/composer', 'git@github.com:composer/composer.git'),
  223. // if restricted to https then push url is not overwritten to git@
  224. array(array('https'), 'https://github.com/composer/composer', 'https://github.com/composer/composer.git'),
  225. );
  226. }
  227. /**
  228. * @dataProvider pushUrlProvider
  229. */
  230. public function testDownloadAndSetPushUrlUseCustomVariousProtocolsForGithub($protocols, $url, $pushUrl)
  231. {
  232. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  233. $packageMock->expects($this->any())
  234. ->method('getSourceReference')
  235. ->will($this->returnValue('ref'));
  236. $packageMock->expects($this->any())
  237. ->method('getSourceUrls')
  238. ->will($this->returnValue(array('https://github.com/composer/composer')));
  239. $packageMock->expects($this->any())
  240. ->method('getSourceUrl')
  241. ->will($this->returnValue('https://github.com/composer/composer'));
  242. $packageMock->expects($this->any())
  243. ->method('getPrettyVersion')
  244. ->will($this->returnValue('1.0.0'));
  245. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  246. $processExecutor->expects($this->at(0))
  247. ->method('execute')
  248. ->with($this->equalTo($this->winCompat('git --version')))
  249. ->will($this->returnCallback(function($command, &$output = null) {
  250. $output = 'git version 1.0.0';
  251. return 0;
  252. }));
  253. $expectedGitCommand = $this->winCompat("git clone --no-checkout '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer '{$url}' && git fetch composer");
  254. $processExecutor->expects($this->at(1))
  255. ->method('execute')
  256. ->with($this->equalTo($expectedGitCommand))
  257. ->will($this->returnValue(0));
  258. $expectedGitCommand = $this->winCompat("git remote set-url --push origin '{$pushUrl}'");
  259. $processExecutor->expects($this->at(2))
  260. ->method('execute')
  261. ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath')))
  262. ->will($this->returnValue(0));
  263. $processExecutor->expects($this->exactly(5))
  264. ->method('execute')
  265. ->will($this->returnValue(0));
  266. $config = new Config();
  267. $config->merge(array('config' => array('github-protocols' => $protocols)));
  268. $downloader = $this->getDownloaderMock(null, $config, $processExecutor);
  269. $downloader->download($packageMock, 'composerPath');
  270. }
  271. /**
  272. * @expectedException \RuntimeException
  273. */
  274. public function testDownloadThrowsRuntimeExceptionIfGitCommandFails()
  275. {
  276. $expectedGitCommand = $this->winCompat("git clone --no-checkout 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer 'https://example.com/composer/composer' && git fetch composer");
  277. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  278. $packageMock->expects($this->any())
  279. ->method('getSourceReference')
  280. ->will($this->returnValue('ref'));
  281. $packageMock->expects($this->any())
  282. ->method('getSourceUrls')
  283. ->will($this->returnValue(array('https://example.com/composer/composer')));
  284. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  285. $processExecutor->expects($this->at(0))
  286. ->method('execute')
  287. ->with($this->equalTo($this->winCompat('git --version')))
  288. ->will($this->returnCallback(function($command, &$output = null) {
  289. $output = 'git version 1.0.0';
  290. return 0;
  291. }));
  292. $processExecutor->expects($this->at(1))
  293. ->method('execute')
  294. ->with($this->equalTo($expectedGitCommand))
  295. ->will($this->returnValue(1));
  296. $downloader = $this->getDownloaderMock(null, null, $processExecutor);
  297. $downloader->download($packageMock, 'composerPath');
  298. }
  299. /**
  300. * @expectedException \InvalidArgumentException
  301. */
  302. public function testUpdateforPackageWithoutSourceReference()
  303. {
  304. $initialPackageMock = $this->getMock('Composer\Package\PackageInterface');
  305. $sourcePackageMock = $this->getMock('Composer\Package\PackageInterface');
  306. $sourcePackageMock->expects($this->once())
  307. ->method('getSourceReference')
  308. ->will($this->returnValue(null));
  309. $downloader = $this->getDownloaderMock();
  310. $downloader->update($initialPackageMock, $sourcePackageMock, '/path');
  311. }
  312. public function testUpdate()
  313. {
  314. $expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
  315. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  316. $packageMock->expects($this->any())
  317. ->method('getSourceReference')
  318. ->will($this->returnValue('ref'));
  319. $packageMock->expects($this->any())
  320. ->method('getSourceUrls')
  321. ->will($this->returnValue(array('https://github.com/composer/composer')));
  322. $packageMock->expects($this->any())
  323. ->method('getPrettyVersion')
  324. ->will($this->returnValue('1.0.0'));
  325. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  326. $processExecutor->expects($this->at(0))
  327. ->method('execute')
  328. ->with($this->equalTo($this->winCompat("git show-ref --head -d")))
  329. ->will($this->returnValue(0));
  330. $processExecutor->expects($this->at(1))
  331. ->method('execute')
  332. ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no")))
  333. ->will($this->returnValue(0));
  334. $processExecutor->expects($this->at(2))
  335. ->method('execute')
  336. ->with($this->equalTo($this->winCompat("git remote -v")))
  337. ->will($this->returnValue(0));
  338. $processExecutor->expects($this->at(3))
  339. ->method('execute')
  340. ->with($this->equalTo($this->winCompat("git remote -v")))
  341. ->will($this->returnValue(0));
  342. $processExecutor->expects($this->at(4))
  343. ->method('execute')
  344. ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  345. ->will($this->returnValue(0));
  346. $processExecutor->expects($this->at(5))
  347. ->method('execute')
  348. ->with($this->equalTo('git branch -r'))
  349. ->will($this->returnValue(0));
  350. $processExecutor->expects($this->at(6))
  351. ->method('execute')
  352. ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  353. ->will($this->returnValue(0));
  354. $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
  355. $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
  356. $downloader->update($packageMock, $packageMock, $this->workingDir);
  357. }
  358. public function testUpdateWithNewRepoUrl()
  359. {
  360. $expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
  361. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  362. $packageMock->expects($this->any())
  363. ->method('getSourceReference')
  364. ->will($this->returnValue('ref'));
  365. $packageMock->expects($this->any())
  366. ->method('getSourceUrls')
  367. ->will($this->returnValue(array('https://github.com/composer/composer')));
  368. $packageMock->expects($this->any())
  369. ->method('getSourceUrl')
  370. ->will($this->returnValue('https://github.com/composer/composer'));
  371. $packageMock->expects($this->any())
  372. ->method('getPrettyVersion')
  373. ->will($this->returnValue('1.0.0'));
  374. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  375. $processExecutor->expects($this->at(0))
  376. ->method('execute')
  377. ->with($this->equalTo($this->winCompat("git show-ref --head -d")))
  378. ->will($this->returnValue(0));
  379. $processExecutor->expects($this->at(1))
  380. ->method('execute')
  381. ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no")))
  382. ->will($this->returnValue(0));
  383. $processExecutor->expects($this->at(2))
  384. ->method('execute')
  385. ->with($this->equalTo($this->winCompat("git remote -v")))
  386. ->will($this->returnCallback(function ($cmd, &$output, $cwd) {
  387. $output = 'origin https://github.com/old/url (fetch)
  388. origin https://github.com/old/url (push)
  389. composer https://github.com/old/url (fetch)
  390. composer https://github.com/old/url (push)
  391. ';
  392. return 0;
  393. }));
  394. $processExecutor->expects($this->at(3))
  395. ->method('execute')
  396. ->with($this->equalTo($this->winCompat("git remote -v")))
  397. ->will($this->returnValue(0));
  398. $processExecutor->expects($this->at(4))
  399. ->method('execute')
  400. ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  401. ->will($this->returnValue(0));
  402. $processExecutor->expects($this->at(5))
  403. ->method('execute')
  404. ->with($this->equalTo('git branch -r'))
  405. ->will($this->returnValue(0));
  406. $processExecutor->expects($this->at(6))
  407. ->method('execute')
  408. ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  409. ->will($this->returnValue(0));
  410. $processExecutor->expects($this->at(7))
  411. ->method('execute')
  412. ->with($this->equalTo($this->winCompat("git remote set-url origin 'https://github.com/composer/composer'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  413. ->will($this->returnValue(0));
  414. $processExecutor->expects($this->at(8))
  415. ->method('execute')
  416. ->with($this->equalTo($this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  417. ->will($this->returnValue(0));
  418. $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
  419. $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
  420. $downloader->update($packageMock, $packageMock, $this->workingDir);
  421. }
  422. /**
  423. * @group failing
  424. * @expectedException \RuntimeException
  425. */
  426. public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
  427. {
  428. $expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
  429. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  430. $packageMock->expects($this->any())
  431. ->method('getSourceReference')
  432. ->will($this->returnValue('ref'));
  433. $packageMock->expects($this->any())
  434. ->method('getSourceUrls')
  435. ->will($this->returnValue(array('https://github.com/composer/composer')));
  436. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  437. $processExecutor->expects($this->at(0))
  438. ->method('execute')
  439. ->with($this->equalTo($this->winCompat("git show-ref --head -d")))
  440. ->will($this->returnValue(0));
  441. $processExecutor->expects($this->at(1))
  442. ->method('execute')
  443. ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no")))
  444. ->will($this->returnValue(0));
  445. $processExecutor->expects($this->at(2))
  446. ->method('execute')
  447. ->with($this->equalTo($this->winCompat("git remote -v")))
  448. ->will($this->returnValue(0));
  449. $processExecutor->expects($this->at(3))
  450. ->method('execute')
  451. ->with($this->equalTo($this->winCompat("git remote -v")))
  452. ->will($this->returnValue(0));
  453. $processExecutor->expects($this->at(4))
  454. ->method('execute')
  455. ->with($this->equalTo($expectedGitUpdateCommand))
  456. ->will($this->returnValue(1));
  457. $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
  458. $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
  459. $downloader->update($packageMock, $packageMock, $this->workingDir);
  460. }
  461. public function testUpdateDoesntThrowsRuntimeExceptionIfGitCommandFailsAtFirstButIsAbleToRecover()
  462. {
  463. $expectedFirstGitUpdateCommand = $this->winCompat("git remote set-url composer '' && git fetch composer && git fetch --tags composer");
  464. $expectedSecondGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer");
  465. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  466. $packageMock->expects($this->any())
  467. ->method('getSourceReference')
  468. ->will($this->returnValue('ref'));
  469. $packageMock->expects($this->any())
  470. ->method('getSourceUrls')
  471. ->will($this->returnValue(array('/foo/bar', 'https://github.com/composer/composer')));
  472. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  473. $processExecutor->expects($this->at(0))
  474. ->method('execute')
  475. ->with($this->equalTo($this->winCompat("git show-ref --head -d")))
  476. ->will($this->returnValue(0));
  477. $processExecutor->expects($this->at(1))
  478. ->method('execute')
  479. ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no")))
  480. ->will($this->returnValue(0));
  481. $processExecutor->expects($this->at(2))
  482. ->method('execute')
  483. ->with($this->equalTo($this->winCompat("git remote -v")))
  484. ->will($this->returnValue(0));
  485. $processExecutor->expects($this->at(3))
  486. ->method('execute')
  487. ->with($this->equalTo($this->winCompat("git remote -v")))
  488. ->will($this->returnValue(0));
  489. $processExecutor->expects($this->at(4))
  490. ->method('execute')
  491. ->with($this->equalTo($expectedFirstGitUpdateCommand))
  492. ->will($this->returnValue(1));
  493. $processExecutor->expects($this->at(6))
  494. ->method('execute')
  495. ->with($this->equalTo($this->winCompat("git --version")))
  496. ->will($this->returnValue(0));
  497. $processExecutor->expects($this->at(7))
  498. ->method('execute')
  499. ->with($this->equalTo($this->winCompat("git remote -v")))
  500. ->will($this->returnValue(0));
  501. $processExecutor->expects($this->at(8))
  502. ->method('execute')
  503. ->with($this->equalTo($this->winCompat("git remote -v")))
  504. ->will($this->returnValue(0));
  505. $processExecutor->expects($this->at(9))
  506. ->method('execute')
  507. ->with($this->equalTo($expectedSecondGitUpdateCommand))
  508. ->will($this->returnValue(0));
  509. $processExecutor->expects($this->at(11))
  510. ->method('execute')
  511. ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir)))
  512. ->will($this->returnValue(0));
  513. $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
  514. $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
  515. $downloader->update($packageMock, $packageMock, $this->workingDir);
  516. }
  517. public function testRemove()
  518. {
  519. $expectedGitResetCommand = $this->winCompat("cd 'composerPath' && git status --porcelain --untracked-files=no");
  520. $packageMock = $this->getMock('Composer\Package\PackageInterface');
  521. $processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
  522. $processExecutor->expects($this->any())
  523. ->method('execute')
  524. ->with($this->equalTo($expectedGitResetCommand))
  525. ->will($this->returnValue(0));
  526. $filesystem = $this->getMock('Composer\Util\Filesystem');
  527. $filesystem->expects($this->any())
  528. ->method('removeDirectory')
  529. ->with($this->equalTo('composerPath'))
  530. ->will($this->returnValue(true));
  531. $downloader = $this->getDownloaderMock(null, null, $processExecutor, $filesystem);
  532. $downloader->remove($packageMock, 'composerPath');
  533. }
  534. public function testGetInstallationSource()
  535. {
  536. $downloader = $this->getDownloaderMock();
  537. $this->assertEquals('source', $downloader->getInstallationSource());
  538. }
  539. private function winCompat($cmd)
  540. {
  541. if (Platform::isWindows()) {
  542. $cmd = str_replace('cd ', 'cd /D ', $cmd);
  543. $cmd = str_replace('composerPath', getcwd().'/composerPath', $cmd);
  544. return str_replace('""', '', strtr($cmd, "'", '"'));
  545. }
  546. return $cmd;
  547. }
  548. }