From 3b1f4cf28c38301bee782d857045c792211e3578 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Wed, 23 Jul 2025 14:19:32 +0100 Subject: [PATCH 1/8] Fix: preserve existing store labels when updating attribute option via API (issue #40093) --- .../Entity/Attribute/OptionManagement.php | 17 ++++++++-- .../ResourceModel/Entity/Attribute/Option.php | 18 +++++++++++ .../Entity/Attribute/OptionManagementTest.php | 32 +++++++++++++++---- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php index 2c9b6d68b0bbf..44c34d052699c 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php @@ -13,6 +13,7 @@ use Magento\Eav\Api\Data\AttributeOptionInterface; use Magento\Eav\Model\AttributeRepository; use Magento\Eav\Model\ResourceModel\Entity\Attribute; +use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; @@ -32,17 +33,25 @@ class OptionManagement implements AttributeOptionManagementInterface, AttributeO */ protected $resourceModel; + /** + * @var Attribute\Option + */ + protected Attribute\Option $optionResource; + /** * @param AttributeRepository $attributeRepository * @param Attribute $resourceModel + * @param Option $optionResource * @codeCoverageIgnore */ public function __construct( AttributeRepository $attributeRepository, - Attribute $resourceModel + Attribute $resourceModel, + Attribute\Option $optionResource ) { $this->attributeRepository = $attributeRepository; $this->resourceModel = $resourceModel; + $this->optionResource = $optionResource; } /** @@ -140,6 +149,11 @@ private function saveOption( $options['value'][$optionId][0] = $optionLabel; $options['order'][$optionId] = $option->getSortOrder(); $options['is_default'][$optionId] = $option->getIsDefault(); + + $existingLabels = $this->optionResource->getStoreLabelsByOptionId((int)$optionId); + foreach ($existingLabels as $storeId => $labelText) { + $options['value'][$optionId][$storeId] = $labelText; + } if (is_array($option->getStoreLabels())) { foreach ($option->getStoreLabels() as $label) { $options['value'][$optionId][$label->getStoreId()] = $label->getLabel(); @@ -148,7 +162,6 @@ private function saveOption( if ($option->getIsDefault()) { $attribute->setDefault([$optionId]); } - $attribute->setOption($options); try { $this->resourceModel->save($attribute); diff --git a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Option.php b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Option.php index a7be59e2c05d5..7e8c8b9d288a0 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Option.php +++ b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Option.php @@ -161,4 +161,22 @@ public function getFlatUpdateSelect( return $select; } + + /** + * Get all store labels for a given option ID + * + * @param int $optionId + * @return array [store_id => label] + */ + public function getStoreLabelsByOptionId(int $optionId): array + { + $connection = $this->getConnection(); + $table = $this->getTable('eav_attribute_option_value'); + + $select = $connection->select() + ->from($table, ['store_id', 'value']) + ->where('option_id = ?', $optionId); + + return $connection->fetchPairs($select); + } } diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php index b36e2dd7d5d5b..87ff37af2566d 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php @@ -44,17 +44,23 @@ class OptionManagementTest extends TestCase */ protected $resourceModelMock; + /** + * @var MockObject|Attribute\Option + */ + protected $optionResourceMock; + /** * @inheritdoc */ protected function setUp(): void { $this->attributeRepositoryMock = $this->createMock(AttributeRepository::class); - $this->resourceModelMock = - $this->createMock(Attribute::class); + $this->resourceModelMock = $this->createMock(Attribute::class); + $this->optionResourceMock = $this->createMock(Attribute\Option::class); $this->model = new OptionManagement( $this->attributeRepositoryMock, - $this->resourceModelMock + $this->resourceModelMock, + $this->optionResourceMock ); } @@ -255,6 +261,7 @@ public function testUpdate(string $label): void $optionId => [ 0 => $label, $storeId => $storeLabel, + 5 => 'otherLabelLabel' ], ], 'order' => [ @@ -265,8 +272,17 @@ public function testUpdate(string $label): void ] ]; + $this->optionResourceMock->expects($this->once()) + ->method('getStoreLabelsByOptionId') + ->with($optionId) + ->willReturn([ + 4 => 'oldLabelLabel', + 5 => 'otherLabelLabel' + ]); + $optionMock = $this->getAttributeOption(); - $labelMock = $this->getAttributeOptionLabel(); + $labelMock1 = $this->getAttributeOptionLabel(); + $labelMock2 = $this->getAttributeOptionLabel(); /** @var SourceInterface|MockObject $sourceMock */ $sourceMock = $this->createMock(EavAttributeSource::class); @@ -297,9 +313,11 @@ public function testUpdate(string $label): void $optionMock->method('getLabel')->willReturn($label); $optionMock->method('getSortOrder')->willReturn($sortOder); $optionMock->method('getIsDefault')->willReturn(true); - $optionMock->method('getStoreLabels')->willReturn([$labelMock]); - $labelMock->method('getStoreId')->willReturn($storeId); - $labelMock->method('getLabel')->willReturn($storeLabel); + $optionMock->method('getStoreLabels')->willReturn([$labelMock1, $labelMock2]); + $labelMock1->method('getStoreId')->willReturn($storeId); + $labelMock1->method('getLabel')->willReturn($storeLabel); + $labelMock2->method('getStoreId')->willReturn(5); + $labelMock2->method('getLabel')->willReturn('otherLabelLabel'); $this->resourceModelMock->expects($this->once())->method('save')->with($attributeMock); $this->assertEquals( From e1d2ce868256f1f74505330036ae113bb259ceaa Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Wed, 23 Jul 2025 14:31:40 +0100 Subject: [PATCH 2/8] Fix: preserve existing store labels when updating attribute option via API (issue #40093) - Updated --- .../Magento/Eav/Model/Entity/Attribute/OptionManagement.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php index 44c34d052699c..0aeeb4b5474f4 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php @@ -154,6 +154,7 @@ private function saveOption( foreach ($existingLabels as $storeId => $labelText) { $options['value'][$optionId][$storeId] = $labelText; } + if (is_array($option->getStoreLabels())) { foreach ($option->getStoreLabels() as $label) { $options['value'][$optionId][$label->getStoreId()] = $label->getLabel(); @@ -162,6 +163,7 @@ private function saveOption( if ($option->getIsDefault()) { $attribute->setDefault([$optionId]); } + $attribute->setOption($options); try { $this->resourceModel->save($attribute); From 419e65a1ddb1d7acbb27d7988b96c7bd557d4df7 Mon Sep 17 00:00:00 2001 From: Abhinav Pathak <85945484+glo24157@users.noreply.github.com> Date: Thu, 3 Jul 2025 19:09:09 +0530 Subject: [PATCH 3/8] Update app-projects-boards-automation.config.yaml - Added condition for PR marked as Changes Requested. - Added condition for the issue close to remove from the project. --- ...app-projects-boards-automation.config.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/app-projects-boards-automation.config.yaml b/.github/app-projects-boards-automation.config.yaml index cbc4592482495..4c84037666a1c 100644 --- a/.github/app-projects-boards-automation.config.yaml +++ b/.github/app-projects-boards-automation.config.yaml @@ -231,6 +231,18 @@ automations: - removeFromProject: [23] #['Pull Requests Dashboard'] - removeFromProject: [22] #['Community Dashboard'] + # 19. Whenever a pull request is marked as changes requested: + # a. the below labels must be removed from a pull request: "Progress: review" + # b. it must be moved to the "Changes Requested" column + - trigger: pull_request_review.submitted + conditions: + - ['review', 'eq', 'changes_requested'] + actions: + - removeLabels: ['Progress: review'] + - addLabels: ['Progress: needs update'] + - moveTo: [23, 'Changes Requested'] #['Pull Requests Dashboard', 'Changes Requested'] + - moveTo: [22, 'Changes Requested'] #['Community Dashboard', 'Changes Requested'] + ############################################################################################################ # Issues Automation # @@ -401,3 +413,10 @@ automations: ] actions: - addLabelsToRelated: ['${modifiedLabel.name}'] + + - trigger: issues.closed + actions: + - removeFromProject: [18] + - removeFromProject: [21] + - removeFromProject: [20] + - removeFromProject: [19] From 8a12edee46d72ab59844691f7f17b8115f7a0f6c Mon Sep 17 00:00:00 2001 From: Abhinav Pathak <85945484+glo24157@users.noreply.github.com> Date: Thu, 17 Jul 2025 20:00:14 +0530 Subject: [PATCH 4/8] Update app-projects-boards-automation.config.yaml Removed condition PR changes requested --- .github/app-projects-boards-automation.config.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/app-projects-boards-automation.config.yaml b/.github/app-projects-boards-automation.config.yaml index 4c84037666a1c..6d69ed06cbc8d 100644 --- a/.github/app-projects-boards-automation.config.yaml +++ b/.github/app-projects-boards-automation.config.yaml @@ -231,18 +231,6 @@ automations: - removeFromProject: [23] #['Pull Requests Dashboard'] - removeFromProject: [22] #['Community Dashboard'] - # 19. Whenever a pull request is marked as changes requested: - # a. the below labels must be removed from a pull request: "Progress: review" - # b. it must be moved to the "Changes Requested" column - - trigger: pull_request_review.submitted - conditions: - - ['review', 'eq', 'changes_requested'] - actions: - - removeLabels: ['Progress: review'] - - addLabels: ['Progress: needs update'] - - moveTo: [23, 'Changes Requested'] #['Pull Requests Dashboard', 'Changes Requested'] - - moveTo: [22, 'Changes Requested'] #['Community Dashboard', 'Changes Requested'] - ############################################################################################################ # Issues Automation # From fac77b416652f282d6459d265568e11d44083e04 Mon Sep 17 00:00:00 2001 From: Abhinav Pathak <85945484+glo24157@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:42:53 +0530 Subject: [PATCH 5/8] Update app-projects-boards-automation.config.yaml Added copyright information in the file --- .github/app-projects-boards-automation.config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/app-projects-boards-automation.config.yaml b/.github/app-projects-boards-automation.config.yaml index 6d69ed06cbc8d..4810f7cfa69fe 100644 --- a/.github/app-projects-boards-automation.config.yaml +++ b/.github/app-projects-boards-automation.config.yaml @@ -1,3 +1,6 @@ +# Copyright 2025 Adobe +# All Rights Reserved. + automations: ############################################################################################################ From 5924fd9e426ddbcc6a520276180c9a975e51d8bf Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Wed, 23 Jul 2025 17:23:02 +0100 Subject: [PATCH 6/8] Fix: preserve existing store labels when updating attribute option via API (issue #40093) - Updated --- .../Eav/Model/Entity/Attribute/OptionManagement.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php index 0aeeb4b5474f4..3c8c53279c6a2 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php @@ -14,6 +14,7 @@ use Magento\Eav\Model\AttributeRepository; use Magento\Eav\Model\ResourceModel\Entity\Attribute; use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; @@ -41,17 +42,17 @@ class OptionManagement implements AttributeOptionManagementInterface, AttributeO /** * @param AttributeRepository $attributeRepository * @param Attribute $resourceModel - * @param Option $optionResource + * @param Option|null $optionResource * @codeCoverageIgnore */ public function __construct( AttributeRepository $attributeRepository, Attribute $resourceModel, - Attribute\Option $optionResource + ?Attribute\Option $optionResource = null ) { $this->attributeRepository = $attributeRepository; $this->resourceModel = $resourceModel; - $this->optionResource = $optionResource; + $this->optionResource = $optionResource ?: ObjectManager::getInstance()->get(Attribute\Option::class); } /** From 193152da9f301d39b691e9546f849a5cc932e122 Mon Sep 17 00:00:00 2001 From: Abhinav Pathak <85945484+glo24157@users.noreply.github.com> Date: Thu, 3 Jul 2025 19:09:09 +0530 Subject: [PATCH 7/8] Update app-projects-boards-automation.config.yaml - Added condition for PR marked as Changes Requested. - Added condition for the issue close to remove from the project. --- .github/app-projects-boards-automation.config.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/app-projects-boards-automation.config.yaml b/.github/app-projects-boards-automation.config.yaml index 4810f7cfa69fe..a6d53770a4751 100644 --- a/.github/app-projects-boards-automation.config.yaml +++ b/.github/app-projects-boards-automation.config.yaml @@ -234,6 +234,18 @@ automations: - removeFromProject: [23] #['Pull Requests Dashboard'] - removeFromProject: [22] #['Community Dashboard'] + # 19. Whenever a pull request is marked as changes requested: + # a. the below labels must be removed from a pull request: "Progress: review" + # b. it must be moved to the "Changes Requested" column + - trigger: pull_request_review.submitted + conditions: + - ['review', 'eq', 'changes_requested'] + actions: + - removeLabels: ['Progress: review'] + - addLabels: ['Progress: needs update'] + - moveTo: [23, 'Changes Requested'] #['Pull Requests Dashboard', 'Changes Requested'] + - moveTo: [22, 'Changes Requested'] #['Community Dashboard', 'Changes Requested'] + ############################################################################################################ # Issues Automation # From a26d9175347c6b21961e314cdb50ac326143a5f1 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Wed, 23 Jul 2025 18:34:46 +0100 Subject: [PATCH 8/8] Static check --- .../Magento/Eav/Model/Entity/Attribute/OptionManagement.php | 4 ++-- .../Eav/Model/ResourceModel/Entity/Attribute/Option.php | 6 ++---- .../Unit/Model/Entity/Attribute/OptionManagementTest.php | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php index 3c8c53279c6a2..184c17c82a742 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php @@ -1,7 +1,7 @@ */ class Option extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php index 87ff37af2566d..3caefc014c9e0 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php @@ -1,7 +1,7 @@