@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve ApplicationTransaction behavior for poorly constructed transactions

Summary:
Ref T2222. Five very small improvements:

- I hit this exception and it took a bit to understand which transaction was causing problems. Add an `Exception` subclass which does a better job of making the message debuggable.
- The `oldValue` of a transaction may be `null`, legitimately (for example, changing the `repositoryPHID` for a revision from `null` to some valid PHID). Do a check to see if `setOldValue()` has been called, instead of a check for a `null` value.
- Add an additional check for the other case (shouldn't have a value, but does).
- When we're not generating a value, don't bother calling the code to generate it. The best case scenario is that it has no effect; any effect it might have (changing the value) is always wrong.
- Maniphest didn't fall back to the parent correctly when computing this flag, so it got the wrong result for `CustomField` transactions.

Test Plan: Resolved the issue I was hitting more easily, made updates to a `null`-valued custom field, and applied other normal sorts of transactions successfully.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T4557, T2222

Differential Revision: https://secure.phabricator.com/D8401

+82 -26
+2
src/__phutil_library_map__.php
··· 1196 1196 'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php', 1197 1197 'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php', 1198 1198 'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php', 1199 + 'PhabricatorApplicationTransactionStructureException' => 'applications/transactions/exception/PhabricatorApplicationTransactionStructureException.php', 1199 1200 'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php', 1200 1201 'PhabricatorApplicationTransactionValidationError' => 'applications/transactions/error/PhabricatorApplicationTransactionValidationError.php', 1201 1202 'PhabricatorApplicationTransactionValidationException' => 'applications/transactions/exception/PhabricatorApplicationTransactionValidationException.php', ··· 3895 3896 'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'PhabricatorPHIDType', 3896 3897 'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3897 3898 'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse', 3899 + 'PhabricatorApplicationTransactionStructureException' => 'Exception', 3898 3900 'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView', 3899 3901 'PhabricatorApplicationTransactionValidationError' => 'Phobject', 3900 3902 'PhabricatorApplicationTransactionValidationException' => 'Exception',
+3 -7
src/applications/maniphest/storage/ManiphestTransaction.php
··· 28 28 } 29 29 30 30 public function shouldGenerateOldValue() { 31 - $generate = true; 32 31 switch ($this->getTransactionType()) { 33 32 case self::TYPE_PROJECT_COLUMN: 34 33 case self::TYPE_EDGE: 35 - $generate = false; 36 - break; 37 - default: 38 - $generate = true; 39 - break; 34 + return false; 40 35 } 41 - return $generate; 36 + 37 + return parent::shouldGenerateOldValue(); 42 38 } 43 39 44 40 public function getRequiredHandlePHIDs() {
+46 -19
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 122 122 private function adjustTransactionValues( 123 123 PhabricatorLiskDAO $object, 124 124 PhabricatorApplicationTransaction $xaction) { 125 - $old = $this->getTransactionOldValue($object, $xaction); 126 - $xaction->setOldValue($old); 125 + 126 + if ($xaction->shouldGenerateOldValue()) { 127 + $old = $this->getTransactionOldValue($object, $xaction); 128 + $xaction->setOldValue($old); 129 + } 127 130 128 131 $new = $this->getTransactionNewValue($object, $xaction); 129 132 $xaction->setNewValue($new); ··· 723 726 assert_instances_of($xactions, 'PhabricatorApplicationTransaction'); 724 727 foreach ($xactions as $xaction) { 725 728 if ($xaction->getPHID() || $xaction->getID()) { 726 - throw new Exception( 727 - "You can not apply transactions which already have IDs/PHIDs!"); 729 + throw new PhabricatorApplicationTransactionStructureException( 730 + $xaction, 731 + pht( 732 + "You can not apply transactions which already have IDs/PHIDs!")); 728 733 } 729 734 if ($xaction->getObjectPHID()) { 730 - throw new Exception( 731 - "You can not apply transactions which already have objectPHIDs!"); 735 + throw new PhabricatorApplicationTransactionStructureException( 736 + $xaction, 737 + pht( 738 + "You can not apply transactions which already have objectPHIDs!")); 732 739 } 733 740 if ($xaction->getAuthorPHID()) { 734 - throw new Exception( 735 - "You can not apply transactions which already have authorPHIDs!"); 741 + throw new PhabricatorApplicationTransactionStructureException( 742 + $xaction, 743 + pht( 744 + 'You can not apply transactions which already have authorPHIDs!')); 736 745 } 737 746 if ($xaction->getCommentPHID()) { 738 - throw new Exception( 739 - "You can not apply transactions which already have commentPHIDs!"); 747 + throw new PhabricatorApplicationTransactionStructureException( 748 + $xaction, 749 + pht( 750 + 'You can not apply transactions which already have '. 751 + 'commentPHIDs!')); 740 752 } 741 753 if ($xaction->getCommentVersion() !== 0) { 742 - throw new Exception( 743 - "You can not apply transactions which already have commentVersions!"); 754 + throw new PhabricatorApplicationTransactionStructureException( 755 + $xaction, 756 + pht( 757 + 'You can not apply transactions which already have '. 758 + 'commentVersions!')); 744 759 } 745 760 746 - if (!$xaction->shouldGenerateOldValue()) { 747 - if ($xaction->getOldValue() === null) { 748 - throw new Exception( 749 - 'You can not apply transactions which should already have '. 750 - 'oldValue but do not!'); 751 - } 761 + $expect_value = !$xaction->shouldGenerateOldValue(); 762 + $has_value = $xaction->hasOldValue(); 763 + 764 + if ($expect_value && !$has_value) { 765 + throw new PhabricatorApplicationTransactionStructureException( 766 + $xaction, 767 + pht( 768 + 'This transaction is supposed to have an oldValue set, but '. 769 + 'it does not!')); 770 + } 771 + 772 + if ($has_value && !$expect_value) { 773 + throw new PhabricatorApplicationTransactionStructureException( 774 + $xaction, 775 + pht( 776 + 'This transaction should generate its oldValue automatically, '. 777 + 'but has already had one set!')); 752 778 } 753 779 754 780 $type = $xaction->getTransactionType(); 755 781 if (empty($types[$type])) { 756 - throw new Exception( 782 + throw new PhabricatorApplicationTransactionStructureException( 783 + $xaction, 757 784 pht( 758 785 'Transaction has type "%s", but that transaction type is not '. 759 786 'supported by this editor (%s).',
+20
src/applications/transactions/exception/PhabricatorApplicationTransactionStructureException.php
··· 1 + <?php 2 + 3 + final class PhabricatorApplicationTransactionStructureException 4 + extends Exception { 5 + 6 + public function __construct( 7 + PhabricatorApplicationTransaction $xaction, 8 + $message) { 9 + 10 + $full_message = pht( 11 + 'Attempting to apply a transaction (of class "%s", with type "%s") '. 12 + 'which has not been constructed correctly: %s', 13 + get_class($xaction), 14 + $xaction->getTransactionType(), 15 + $message); 16 + 17 + parent::__construct($full_message); 18 + } 19 + 20 + }
+11
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 30 30 private $transactionGroup = array(); 31 31 private $viewer = self::ATTACHABLE; 32 32 private $object = self::ATTACHABLE; 33 + private $oldValueHasBeenSet = false; 33 34 34 35 private $ignoreOnNoEffect; 35 36 ··· 167 168 } 168 169 169 170 return $blocks; 171 + } 172 + 173 + public function setOldValue($value) { 174 + $this->oldValueHasBeenSet = true; 175 + $this->writeField('oldValue', $value); 176 + return $this; 177 + } 178 + 179 + public function hasOldValue() { 180 + return $this->oldValueHasBeenSet; 170 181 } 171 182 172 183