Skip to content

Commit 6fb1f9c

Browse files
committed
Fixing bug where files failed to delete that were modified previously
1 parent 22c14c5 commit 6fb1f9c

File tree

5 files changed

+83
-72
lines changed

5 files changed

+83
-72
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
matrix:
2121
include:
2222
- php: '7.1'
23+
composer: 2.2.x
2324
- php: '7.2'
2425
- php: '7.3'
2526
- php: '7.4'
@@ -33,11 +34,11 @@ jobs:
3334
uses: actions/checkout@v2.3.3
3435

3536
- name: "Install PHP with extensions"
36-
uses: shivammathur/setup-php@2.7.0
37+
uses: shivammathur/setup-php@2.18.0
3738
with:
3839
coverage: "none"
3940
php-version: ${{ matrix.php }}
40-
tools: composer:v2
41+
tools: composer:${{ matrix.composer }}
4142

4243
- name: "Validate composer.json"
4344
run: "composer validate --strict --no-check-lock"

src/Update/RecipePatch.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ class RecipePatch
1515
{
1616
private $patch;
1717
private $blobs;
18+
private $deletedFiles;
1819
private $removedPatches;
1920

20-
public function __construct(string $patch, array $blobs, array $removedPatches = [])
21+
public function __construct(string $patch, array $blobs, array $deletedFiles, array $removedPatches = [])
2122
{
2223
$this->patch = $patch;
2324
$this->blobs = $blobs;
25+
$this->deletedFiles = $deletedFiles;
2426
$this->removedPatches = $removedPatches;
2527
}
2628

@@ -34,6 +36,11 @@ public function getBlobs(): array
3436
return $this->blobs;
3537
}
3638

39+
public function getDeletedFiles(): array
40+
{
41+
return $this->deletedFiles;
42+
}
43+
3744
/**
3845
* Patches for modified files that were removed because the file
3946
* has been deleted in the user's project.

src/Update/RecipePatcher.php

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,13 @@ public function __construct(string $rootDir, IOInterface $io)
3838
*/
3939
public function applyPatch(RecipePatch $patch): bool
4040
{
41-
if (!$patch->getPatch()) {
42-
// nothing to do!
43-
return true;
44-
}
45-
46-
$addedBlobs = $this->addMissingBlobs($patch->getBlobs());
47-
48-
$patchPath = $this->rootDir.'/_flex_recipe_update.patch';
49-
file_put_contents($patchPath, $patch->getPatch());
41+
$withConflicts = $this->_applyPatchFile($patch);
5042

51-
try {
52-
$this->execute('git update-index --refresh', $this->rootDir);
53-
54-
$output = '';
55-
$statusCode = $this->processExecutor->execute('git apply "_flex_recipe_update.patch" -3', $output, $this->rootDir);
56-
57-
if (0 === $statusCode) {
58-
// successful with no conflicts
59-
return true;
60-
}
61-
62-
if (false !== strpos($this->processExecutor->getErrorOutput(), 'with conflicts')) {
63-
// successful with conflicts
64-
return false;
65-
}
66-
67-
throw new \LogicException('Error applying the patch: '.$this->processExecutor->getErrorOutput());
68-
} finally {
69-
unlink($patchPath);
70-
// clean up any temporary blobs
71-
foreach ($addedBlobs as $filename) {
72-
unlink($filename);
73-
}
43+
foreach ($patch->getDeletedFiles() as $deletedFile) {
44+
$this->execute(sprintf('git rm %s', ProcessExecutor::escape($deletedFile)), $this->rootDir);
7445
}
46+
47+
return $withConflicts;
7548
}
7649

7750
public function generatePatch(array $originalFiles, array $newFiles): RecipePatch
@@ -84,10 +57,13 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
8457
return null !== $file;
8558
});
8659

87-
// find removed files and add them so they will be deleted
60+
$deletedFiles = [];
61+
// find removed files & record that they are deleted
62+
// unset them from originalFiles to avoid unnecessary blobs being added
8863
foreach ($originalFiles as $file => $contents) {
8964
if (!isset($newFiles[$file])) {
90-
$newFiles[$file] = null;
65+
$deletedFiles[] = $file;
66+
unset($originalFiles[$file]);
9167
}
9268
}
9369

@@ -130,6 +106,7 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
130106
return new RecipePatch(
131107
$patchString,
132108
$blobs,
109+
$deletedFiles,
133110
$removedPatches
134111
);
135112
} finally {
@@ -223,4 +200,42 @@ private function getBlobPath(string $hash): string
223200

224201
return '.git/objects/'.$hashStart.'/'.$hashEnd;
225202
}
203+
204+
private function _applyPatchFile(RecipePatch $patch)
205+
{
206+
if (!$patch->getPatch()) {
207+
// nothing to do!
208+
return true;
209+
}
210+
211+
$addedBlobs = $this->addMissingBlobs($patch->getBlobs());
212+
213+
$patchPath = $this->rootDir.'/_flex_recipe_update.patch';
214+
file_put_contents($patchPath, $patch->getPatch());
215+
216+
try {
217+
$this->execute('git update-index --refresh', $this->rootDir);
218+
219+
$output = '';
220+
$statusCode = $this->processExecutor->execute('git apply "_flex_recipe_update.patch" -3', $output, $this->rootDir);
221+
222+
if (0 === $statusCode) {
223+
// successful with no conflicts
224+
return true;
225+
}
226+
227+
if (false !== strpos($this->processExecutor->getErrorOutput(), 'with conflicts')) {
228+
// successful with conflicts
229+
return false;
230+
}
231+
232+
throw new \LogicException('Error applying the patch: '.$this->processExecutor->getErrorOutput());
233+
} finally {
234+
unlink($patchPath);
235+
// clean up any temporary blobs
236+
foreach ($addedBlobs as $filename) {
237+
unlink($filename);
238+
}
239+
}
240+
}
226241
}

tests/Update/RecipePatchTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ public function testBasicFunctioning()
2020
{
2121
$thePatch = 'the patch';
2222
$blobs = ['blob1', 'blob2', 'beware of the blob'];
23+
$deletedFiles = ['old_file.txt'];
2324
$removedPatches = ['foo' => 'some diff'];
2425

25-
$patch = new RecipePatch($thePatch, $blobs, $removedPatches);
26+
$patch = new RecipePatch($thePatch, $blobs, $deletedFiles, $removedPatches);
2627

2728
$this->assertSame($thePatch, $patch->getPatch());
2829
$this->assertSame($blobs, $patch->getBlobs());
30+
$this->assertSame($deletedFiles, $patch->getDeletedFiles());
2931
$this->assertSame($removedPatches, $patch->getRemovedPatches());
3032
}
3133
}

tests/Update/RecipePatcherTest.php

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected function setUp(): void
3131
/**
3232
* @dataProvider getGeneratePatchTests
3333
*/
34-
public function testGeneratePatch(array $originalFiles, array $newFiles, string $expectedPatch)
34+
public function testGeneratePatch(array $originalFiles, array $newFiles, string $expectedPatch, array $expectedDeletedFiles = [])
3535
{
3636
$this->getFilesystem()->remove(FLEX_TEST_DIR);
3737
$this->getFilesystem()->mkdir(FLEX_TEST_DIR);
@@ -44,6 +44,7 @@ public function testGeneratePatch(array $originalFiles, array $newFiles, string
4444

4545
$patch = $patcher->generatePatch($originalFiles, $newFiles);
4646
$this->assertSame($expectedPatch, rtrim($patch->getPatch(), "\n"));
47+
$this->assertSame($expectedDeletedFiles, $patch->getDeletedFiles());
4748

4849
// find all "index 7d30dc7.." in patch
4950
$matches = [];
@@ -121,31 +122,15 @@ public function getGeneratePatchTests(): iterable
121122
yield 'file_deleted_in_update_because_missing' => [
122123
['file1.txt' => 'New file'],
123124
[],
124-
<<<EOF
125-
diff --git a/file1.txt b/file1.txt
126-
deleted file mode 100644
127-
index b78ca63..0000000
128-
--- a/file1.txt
129-
+++ /dev/null
130-
@@ -1 +0,0 @@
131-
-New file
132-
\ No newline at end of file
133-
EOF
125+
'',
126+
['file1.txt'],
134127
];
135128

136129
yield 'file_deleted_in_update_because_null' => [
137130
['file1.txt' => 'New file'],
138131
['file1.txt' => null],
139-
<<<EOF
140-
diff --git a/file1.txt b/file1.txt
141-
deleted file mode 100644
142-
index b78ca63..0000000
143-
--- a/file1.txt
144-
+++ /dev/null
145-
@@ -1 +0,0 @@
146-
-New file
147-
\ No newline at end of file
148-
EOF
132+
'',
133+
['file1.txt'],
149134
];
150135

151136
yield 'mixture_of_added_updated_removed' => [
@@ -169,15 +154,9 @@ public function getGeneratePatchTests(): iterable
169154
@@ -0,0 +1 @@
170155
+file to create
171156
\ No newline at end of file
172-
diff --git a/will_be_deleted.txt b/will_be_deleted.txt
173-
deleted file mode 100644
174-
index 98ff166..0000000
175-
--- a/will_be_deleted.txt
176-
+++ /dev/null
177-
@@ -1 +0,0 @@
178-
-file to delete
179-
\ No newline at end of file
180157
EOF
158+
,
159+
['will_be_deleted.txt'],
181160
];
182161
}
183162

@@ -243,7 +222,8 @@ public function getApplyPatchTests(): iterable
243222
['.env' => $dotEnvClean['in_app']],
244223
new RecipePatch(
245224
$dotEnvClean['patch'],
246-
[$dotEnvClean['hash'] => $dotEnvClean['blob']]
225+
[$dotEnvClean['hash'] => $dotEnvClean['blob']],
226+
[]
247227
),
248228
['.env' => $dotEnvClean['expected']],
249229
false,
@@ -253,7 +233,8 @@ public function getApplyPatchTests(): iterable
253233
['package.json' => $packageJsonConflict['in_app']],
254234
new RecipePatch(
255235
$packageJsonConflict['patch'],
256-
[$packageJsonConflict['hash'] => $packageJsonConflict['blob']]
236+
[$packageJsonConflict['hash'] => $packageJsonConflict['blob']],
237+
[]
257238
),
258239
['package.json' => $packageJsonConflict['expected']],
259240
true,
@@ -265,6 +246,7 @@ public function getApplyPatchTests(): iterable
265246
new RecipePatch(
266247
$webpackEncoreAdded['patch'],
267248
// no blobs needed for a new file
249+
[],
268250
[]
269251
),
270252
['config/packages/webpack_encore.yaml' => $webpackEncoreAdded['expected']],
@@ -274,8 +256,9 @@ public function getApplyPatchTests(): iterable
274256
yield 'removed_one_file' => [
275257
['config/packages/security.yaml' => $securityRemoved['in_app']],
276258
new RecipePatch(
277-
$securityRemoved['patch'],
278-
[$securityRemoved['hash'] => $securityRemoved['blob']]
259+
'',
260+
[$securityRemoved['hash'] => $securityRemoved['blob']],
261+
['config/packages/security.yaml']
279262
),
280263
// expected to be deleted
281264
['config/packages/security.yaml' => null],
@@ -290,12 +273,15 @@ public function getApplyPatchTests(): iterable
290273
'config/packages/security.yaml' => $securityRemoved['in_app'],
291274
],
292275
new RecipePatch(
293-
$dotEnvClean['patch']."\n".$packageJsonConflict['patch']."\n".$webpackEncoreAdded['patch']."\n".$securityRemoved['patch'],
276+
$dotEnvClean['patch']."\n".$packageJsonConflict['patch']."\n".$webpackEncoreAdded['patch'],
294277
[
295278
$dotEnvClean['hash'] => $dotEnvClean['blob'],
296279
$packageJsonConflict['hash'] => $packageJsonConflict['blob'],
297280
$webpackEncoreAdded['hash'] => $webpackEncoreAdded['blob'],
298281
$securityRemoved['hash'] => $securityRemoved['blob'],
282+
],
283+
[
284+
'config/packages/security.yaml',
299285
]
300286
),
301287
[

0 commit comments

Comments
 (0)