Skip to content

Commit 026a502

Browse files
committed
fixup! fix(systemtags): case-insensitive search & prevent duplicates
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent e275a46 commit 026a502

File tree

5 files changed

+127
-40
lines changed

5 files changed

+127
-40
lines changed

lib/composer/composer/InstalledVersions.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
*/
2727
class InstalledVersions
2828
{
29+
/**
30+
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
31+
* @internal
32+
*/
33+
private static $selfDir = null;
34+
2935
/**
3036
* @var mixed[]|null
3137
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
@@ -322,6 +328,18 @@ public static function reload($data)
322328
self::$installedIsLocalDir = false;
323329
}
324330

331+
/**
332+
* @return string
333+
*/
334+
private static function getSelfDir()
335+
{
336+
if (self::$selfDir === null) {
337+
self::$selfDir = strtr(__DIR__, '\\', '/');
338+
}
339+
340+
return self::$selfDir;
341+
}
342+
325343
/**
326344
* @return array[]
327345
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
@@ -336,7 +354,7 @@ private static function getInstalled()
336354
$copiedLocalDir = false;
337355

338356
if (self::$canGetVendors) {
339-
$selfDir = strtr(__DIR__, '\\', '/');
357+
$selfDir = self::getSelfDir();
340358
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
341359
$vendorDir = strtr($vendorDir, '\\', '/');
342360
if (isset(self::$installedByVendor[$vendorDir])) {
Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,68 @@
11
{
2-
"packages": [],
3-
"dev": false,
4-
"dev-package-names": []
2+
"packages": [
3+
{
4+
"name": "bamarni/composer-bin-plugin",
5+
"version": "1.8.2",
6+
"version_normalized": "1.8.2.0",
7+
"source": {
8+
"type": "git",
9+
"url": "https://github.com/bamarni/composer-bin-plugin.git",
10+
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880"
11+
},
12+
"dist": {
13+
"type": "zip",
14+
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
15+
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
16+
"shasum": ""
17+
},
18+
"require": {
19+
"composer-plugin-api": "^2.0",
20+
"php": "^7.2.5 || ^8.0"
21+
},
22+
"require-dev": {
23+
"composer/composer": "^2.0",
24+
"ext-json": "*",
25+
"phpstan/extension-installer": "^1.1",
26+
"phpstan/phpstan": "^1.8",
27+
"phpstan/phpstan-phpunit": "^1.1",
28+
"phpunit/phpunit": "^8.5 || ^9.5",
29+
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
30+
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
31+
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
32+
},
33+
"time": "2022-10-31T08:38:03+00:00",
34+
"type": "composer-plugin",
35+
"extra": {
36+
"class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin"
37+
},
38+
"installation-source": "dist",
39+
"autoload": {
40+
"psr-4": {
41+
"Bamarni\\Composer\\Bin\\": "src"
42+
}
43+
},
44+
"notification-url": "https://packagist.org/downloads/",
45+
"license": [
46+
"MIT"
47+
],
48+
"description": "No conflicts for your bin dependencies",
49+
"keywords": [
50+
"composer",
51+
"conflict",
52+
"dependency",
53+
"executable",
54+
"isolation",
55+
"tool"
56+
],
57+
"support": {
58+
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
59+
"source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2"
60+
},
61+
"install-path": "../bamarni/composer-bin-plugin"
62+
}
63+
],
64+
"dev": true,
65+
"dev-package-names": [
66+
"bamarni/composer-bin-plugin"
67+
]
568
}

lib/composer/composer/installed.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@
33
'name' => '__root__',
44
'pretty_version' => 'dev-master',
55
'version' => 'dev-master',
6-
'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
6+
'reference' => 'e275a46b7cffae9c526be473e714bf362612be37',
77
'type' => 'library',
88
'install_path' => __DIR__ . '/../../../',
99
'aliases' => array(),
10-
'dev' => false,
10+
'dev' => true,
1111
),
1212
'versions' => array(
1313
'__root__' => array(
1414
'pretty_version' => 'dev-master',
1515
'version' => 'dev-master',
16-
'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
16+
'reference' => 'e275a46b7cffae9c526be473e714bf362612be37',
1717
'type' => 'library',
1818
'install_path' => __DIR__ . '/../../../',
1919
'aliases' => array(),
2020
'dev_requirement' => false,
2121
),
22+
'bamarni/composer-bin-plugin' => array(
23+
'pretty_version' => '1.8.2',
24+
'version' => '1.8.2.0',
25+
'reference' => '92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880',
26+
'type' => 'composer-plugin',
27+
'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin',
28+
'aliases' => array(),
29+
'dev_requirement' => true,
30+
),
2231
),
2332
);

lib/private/SystemTag/SystemTagManager.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ public function updateTag(
234234
$color
235235
);
236236

237+
// Check if tag already exists (case-insensitive)
238+
$existingTags = $this->getAllTags(null, $truncatedNewName);
239+
foreach ($existingTags as $existingTag) {
240+
if ($existingTag->getName() === $truncatedNewName && $existingTag->getId() !== $tagId) {
241+
throw new TagAlreadyExistsException('Tag ' . $truncatedNewName . ' already exists');
242+
}
243+
}
244+
237245
$query = $this->connection->getQueryBuilder();
238246
$query->update(self::TAG_TABLE)
239247
->set('name', $query->createParameter('name'))

tests/lib/SystemTag/SystemTagManagerTest.php

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,6 @@ public static function getAllTagsDataProvider(): array {
8282
['two', false, false],
8383
]
8484
],
85-
[
86-
// duplicate names, different flags
87-
[
88-
['one', false, false],
89-
['one', true, false],
90-
['one', false, true],
91-
['one', true, true],
92-
['two', false, false],
93-
['two', false, true],
94-
]
95-
]
9685
];
9786
}
9887

@@ -163,14 +152,14 @@ public static function getAllTagsFilteredDataProvider(): array {
163152
[
164153
[
165154
['one', true, false],
166-
['one', false, false],
155+
['one_different', false, false],
167156
['two', true, false],
168157
],
169158
null,
170159
'on',
171160
[
172161
['one', true, false],
173-
['one', false, false],
162+
['one_different', false, false],
174163
]
175164
],
176165
// filter by name pattern and visibility
@@ -179,12 +168,13 @@ public static function getAllTagsFilteredDataProvider(): array {
179168
[
180169
['one', true, false],
181170
['two', true, false],
182-
['one', false, false],
171+
['one_different', false, false],
183172
],
184173
true,
185174
'on',
186175
[
187176
['one', true, false],
177+
['one_different', false, false],
188178
]
189179
],
190180
// filter by name pattern in the middle
@@ -246,6 +236,15 @@ public function testCreateDuplicate($name, $userVisible, $userAssignable): void
246236
$this->tagManager->createTag($name, $userVisible, $userAssignable);
247237
}
248238

239+
public function testCreateDuplicateWithDifferentFlags(): void {
240+
$this->expectException(TagAlreadyExistsException::class);
241+
242+
// Create a tag with specific flags
243+
$this->tagManager->createTag('duplicate', true, false);
244+
// Try to create a tag with the same name but different flags - should fail
245+
$this->tagManager->createTag('duplicate', false, true);
246+
}
247+
249248
public function testCreateOverlongName(): void {
250249
$tag = $this->tagManager->createTag('Zona circundante do Palácio Nacional da Ajuda (Jardim das Damas, Salão de Física, Torre Sineira, Paço Velho e Jardim Botânico)', true, true);
251250
$this->assertSame('Zona circundante do Palácio Nacional da Ajuda (Jardim das Damas', $tag->getName()); // 63 characters but 64 bytes due to "á"
@@ -349,30 +348,20 @@ public function testUpdateTag($tagCreate, $tagUpdated): void {
349348

350349
}
351350

352-
#[\PHPUnit\Framework\Attributes\DataProvider('updateTagProvider')]
353-
public function testUpdateTagDuplicate($tagCreate, $tagUpdated): void {
351+
public function testUpdateTagToExistingName(): void {
354352
$this->expectException(TagAlreadyExistsException::class);
355353

356-
$this->tagManager->createTag(
357-
$tagCreate[0],
358-
$tagCreate[1],
359-
$tagCreate[2],
360-
$tagCreate[3],
361-
);
362-
$tag2 = $this->tagManager->createTag(
363-
$tagUpdated[0],
364-
$tagUpdated[1],
365-
$tagUpdated[2],
366-
$tagUpdated[3],
367-
);
354+
// Create two different tags
355+
$tag1 = $this->tagManager->createTag('first', true, true);
356+
$tag2 = $this->tagManager->createTag('second', false, false);
368357

369-
// update to match the first tag
358+
// Try to update tag2 to have the same name as tag1 - should fail
370359
$this->tagManager->updateTag(
371360
$tag2->getId(),
372-
$tagCreate[0],
373-
$tagCreate[1],
374-
$tagCreate[2],
375-
$tagCreate[3],
361+
'first',
362+
false,
363+
false,
364+
null
376365
);
377366
}
378367

0 commit comments

Comments
 (0)