Skip to content

Commit c824772

Browse files
committed
bug #937 Updating Recipe Fails When Project Located in Subfolder in Git Repository (Peukku, Mikko Peltola)
This PR was merged into the 1.x branch. Discussion ---------- Updating Recipe Fails When Project Located in Subfolder in Git Repository Closes #918 and #864 Updating Recipe fails when symfony project is not in the root of git project. As a developer the most problematic thing is that it fails without any errors. Some files are just not updated. There is a simple project with commands needed to reproduce to see what is happening before the fix: https://github.com/Peukku/symfony-flex-reproducer-918-project-root/ I think there are two reasons for this to happen: * $patchString is created with git diff in tmpPath, which has a temporary flat git repository (with no path prefix), but applied bit later in project context where path would be needed. * Location of .git directory is assumed to be in project root, when it actually is in git root level. (or in .git/modules/[subproject] when using git submodules). The blobs do get written, but in the wrong location. This PR uses git binary to resolve location of .git folder and current relative path to be used as the prefix for git diff. Commits ------- 637b769 tweak coding standards 48e5039 Refactored getBlobPath() for clarity, added testApplyPatchOnSubfolder() using same dataprovider as is used for testApplyPatch() ae675dc Use git binary to resolve location of .git folder and current relative path
2 parents 2c5e9cb + 637b769 commit c824772

File tree

2 files changed

+58
-9
lines changed

2 files changed

+58
-9
lines changed

src/Update/RecipePatcher.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
8383
}
8484
}
8585

86+
// Use git binary to get project path from repository root
87+
$prefix = trim($this->execute('git rev-parse --show-prefix', $this->rootDir));
8688
$tmpPath = sys_get_temp_dir().'/_flex_recipe_update'.uniqid(mt_rand(), true);
8789
$this->filesystem->mkdir($tmpPath);
8890

@@ -104,7 +106,7 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
104106
$this->writeFiles($newFiles, $tmpPath);
105107
$this->execute('git add -A', $tmpPath);
106108

107-
$patchString = $this->execute('git diff --cached', $tmpPath);
109+
$patchString = $this->execute(sprintf('git diff --cached --src-prefix "a/%s" --dst-prefix "b/%s"', $prefix, $prefix), $tmpPath);
108110
$removedPatches = [];
109111
$patchString = DiffHelper::removeFilesFromPatch($patchString, $deletedModifiedFiles, $removedPatches);
110112

@@ -167,7 +169,7 @@ private function addMissingBlobs(array $blobs): array
167169
{
168170
$addedBlobs = [];
169171
foreach ($blobs as $hash => $contents) {
170-
$blobPath = $this->rootDir.'/'.$this->getBlobPath($hash);
172+
$blobPath = $this->getBlobPath($this->rootDir, $hash);
171173
if (file_exists($blobPath)) {
172174
continue;
173175
}
@@ -192,18 +194,20 @@ private function generateBlobs(array $originalFiles, string $originalFilesRoot):
192194
}
193195

194196
$hash = trim($this->execute('git hash-object '.ProcessExecutor::escape($filename), $originalFilesRoot));
195-
$addedBlobs[$hash] = file_get_contents($originalFilesRoot.'/'.$this->getBlobPath($hash));
197+
$addedBlobs[$hash] = file_get_contents($this->getBlobPath($originalFilesRoot, $hash));
196198
}
197199

198200
return $addedBlobs;
199201
}
200202

201-
private function getBlobPath(string $hash): string
203+
private function getBlobPath(string $gitRoot, string $hash): string
202204
{
205+
$gitDir = trim($this->execute('git rev-parse --absolute-git-dir', $gitRoot));
206+
203207
$hashStart = substr($hash, 0, 2);
204208
$hashEnd = substr($hash, 2);
205209

206-
return '.git/objects/'.$hashStart.'/'.$hashEnd;
210+
return $gitDir.'/objects/'.$hashStart.'/'.$hashEnd;
207211
}
208212

209213
private function _applyPatchFile(RecipePatch $patch)

tests/Update/RecipePatcherTest.php

+49-4
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,54 @@ public function testApplyPatch(array $filesCurrentlyInApp, RecipePatch $recipePa
233233
$this->assertSame($expectedConflicts, $hadConflicts);
234234
}
235235

236-
public function getApplyPatchTests(): iterable
236+
/**
237+
* @dataProvider getApplyPatchTests
238+
*/
239+
public function testApplyPatchOnSubfolder(array $filesCurrentlyInApp, RecipePatch $recipePatch, array $expectedFiles, bool $expectedConflicts)
237240
{
238-
$files = $this->getFilesForPatching();
241+
$mainProjectPath = FLEX_TEST_DIR;
242+
$subProjectPath = FLEX_TEST_DIR.'/ProjectA';
243+
244+
(new Process(['git', 'init'], $mainProjectPath))->mustRun();
245+
(new Process(['git', 'config', 'user.name', 'Unit test'], $mainProjectPath))->mustRun();
246+
(new Process(['git', 'config', 'user.email', ''], $mainProjectPath))->mustRun();
247+
248+
if (!file_exists($subProjectPath)) {
249+
mkdir($subProjectPath, 0777, true);
250+
}
251+
252+
foreach ($filesCurrentlyInApp as $file => $contents) {
253+
$path = $subProjectPath.'/'.$file;
254+
if (!file_exists(\dirname($path))) {
255+
@mkdir(\dirname($path), 0777, true);
256+
}
257+
file_put_contents($path, $contents);
258+
}
259+
if (\count($filesCurrentlyInApp) > 0) {
260+
(new Process(['git', 'add', '-A'], $subProjectPath))->mustRun();
261+
(new Process(['git', 'commit', '-m', 'Committing original files'], $subProjectPath))->mustRun();
262+
}
263+
264+
$patcher = new RecipePatcher($subProjectPath, $this->createMock(IOInterface::class));
265+
$hadConflicts = !$patcher->applyPatch($recipePatch);
266+
267+
foreach ($expectedFiles as $file => $expectedContents) {
268+
if (null === $expectedContents) {
269+
$this->assertFileDoesNotExist($subProjectPath.'/'.$file);
270+
271+
continue;
272+
}
273+
$this->assertFileExists($subProjectPath.'/'.$file);
274+
$this->assertSame($expectedContents, file_get_contents($subProjectPath.'/'.$file));
275+
}
276+
277+
$this->assertSame($expectedConflicts, $hadConflicts);
278+
}
279+
280+
public function getApplyPatchTests(string $testMethodName): iterable
281+
{
282+
$projectRootPath = ('testApplyPatchOnSubfolder' === $testMethodName) ? 'ProjectA/' : '';
283+
$files = $this->getFilesForPatching($projectRootPath);
239284
$dotEnvClean = $files['dot_env_clean'];
240285
$packageJsonConflict = $files['package_json_conflict'];
241286
$webpackEncoreAdded = $files['webpack_encore_added'];
@@ -393,7 +438,7 @@ public function getIntegrationTests(): iterable
393438
* * original_recipe
394439
* * updated_recipe.
395440
*/
396-
private function getFilesForPatching(): array
441+
private function getFilesForPatching(string $projectPath = ''): array
397442
{
398443
$files = [
399444
// .env
@@ -538,7 +583,7 @@ private function getFilesForPatching(): array
538583
foreach ($files as $key => $data) {
539584
$files[$key] = array_merge(
540585
$data,
541-
$this->generatePatchData($data['filename'], $data['original_recipe'], $data['updated_recipe'])
586+
$this->generatePatchData($projectPath.$data['filename'], $data['original_recipe'], $data['updated_recipe'])
542587
);
543588
}
544589

0 commit comments

Comments
 (0)