@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
at upstream/main 387 lines 13 kB view raw
1<?php 2 3final class DifferentialRevisionEditEngine 4 extends PhabricatorEditEngine { 5 6 private $diff; 7 8 const ENGINECONST = 'differential.revision'; 9 10 const ACTIONGROUP_REVIEW = 'review'; 11 const ACTIONGROUP_REVISION = 'revision'; 12 13 public function getEngineName() { 14 return pht('Revisions'); 15 } 16 17 public function getSummaryHeader() { 18 return pht('Configure Revision Forms'); 19 } 20 21 public function getSummaryText() { 22 return pht( 23 'Configure creation and editing revision forms in Differential.'); 24 } 25 26 public function getEngineApplicationClass() { 27 return PhabricatorDifferentialApplication::class; 28 } 29 30 public function isEngineConfigurable() { 31 return false; 32 } 33 34 protected function newEditableObject() { 35 $viewer = $this->getViewer(); 36 return DifferentialRevision::initializeNewRevision($viewer); 37 } 38 39 protected function newObjectQuery() { 40 return id(new DifferentialRevisionQuery()) 41 ->needActiveDiffs(true) 42 ->needReviewers(true) 43 ->needReviewerAuthority(true); 44 } 45 46 protected function getObjectCreateTitleText($object) { 47 return pht('Create New Revision'); 48 } 49 50 protected function getObjectEditTitleText($object) { 51 $monogram = $object->getMonogram(); 52 $title = $object->getTitle(); 53 54 $diff = $this->getDiff(); 55 if ($diff) { 56 return pht('Update Revision %s: %s', $monogram, $title); 57 } else { 58 return pht('Edit Revision %s: %s', $monogram, $title); 59 } 60 } 61 62 protected function getObjectEditShortText($object) { 63 return $object->getMonogram(); 64 } 65 66 public function getCreateURI($form_key) { 67 return '/differential/diff/create/'; 68 } 69 70 protected function getObjectCreateShortText() { 71 return pht('Create Revision'); 72 } 73 74 protected function getObjectName() { 75 return pht('Revision'); 76 } 77 78 protected function getCommentViewButtonText($object) { 79 if ($object->isDraft()) { 80 return pht('Submit Quietly'); 81 } 82 83 return parent::getCommentViewButtonText($object); 84 } 85 86 protected function getObjectViewURI($object) { 87 return $object->getURI(); 88 } 89 90 protected function getEditorURI() { 91 return $this->getApplication()->getApplicationURI('revision/edit/'); 92 } 93 94 public function setDiff(DifferentialDiff $diff) { 95 $this->diff = $diff; 96 return $this; 97 } 98 99 public function getDiff() { 100 return $this->diff; 101 } 102 103 protected function newCommentActionGroups() { 104 return array( 105 id(new PhabricatorEditEngineCommentActionGroup()) 106 ->setKey(self::ACTIONGROUP_REVIEW) 107 ->setLabel(pht('Review Actions')), 108 id(new PhabricatorEditEngineCommentActionGroup()) 109 ->setKey(self::ACTIONGROUP_REVISION) 110 ->setLabel(pht('Revision Actions')), 111 ); 112 } 113 114 protected function buildCustomEditFields($object) { 115 $viewer = $this->getViewer(); 116 117 $plan_required = PhabricatorEnv::getEnvConfig( 118 'differential.require-test-plan-field'); 119 $plan_enabled = $this->isCustomFieldEnabled( 120 $object, 121 'differential:test-plan'); 122 123 $diff = $this->getDiff(); 124 if ($diff) { 125 $diff_phid = $diff->getPHID(); 126 } else { 127 $diff_phid = null; 128 } 129 130 $is_create = $this->getIsCreate(); 131 $is_update = ($diff && !$is_create); 132 133 $fields = array(); 134 135 $fields[] = id(new PhabricatorHandlesEditField()) 136 ->setKey(DifferentialRevisionUpdateTransaction::EDITKEY) 137 ->setLabel(pht('Update Diff')) 138 ->setDescription(pht('New diff to create or update the revision with.')) 139 ->setConduitDescription(pht('Create or update a revision with a diff.')) 140 ->setConduitTypeDescription(pht('PHID of the diff.')) 141 ->setTransactionType( 142 DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE) 143 ->setHandleParameterType(new AphrontPHIDListHTTPParameterType()) 144 ->setSingleValue($diff_phid) 145 ->setIsFormField((bool)$diff) 146 ->setIsReorderable(false) 147 ->setIsDefaultable(false) 148 ->setIsInvisible(true) 149 ->setIsLockable(false); 150 151 if ($is_update) { 152 $fields[] = id(new PhabricatorInstructionsEditField()) 153 ->setKey('update.help') 154 ->setValue(pht('Describe the updates you have made to the diff.')); 155 $fields[] = id(new PhabricatorCommentEditField()) 156 ->setKey('update.comment') 157 ->setLabel(pht('Comment')) 158 ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 159 ->setIsWebOnly(true) 160 ->setDescription(pht('Comments providing context for the update.')); 161 $fields[] = id(new PhabricatorSubmitEditField()) 162 ->setKey('update.submit') 163 ->setValue($this->getObjectEditButtonText($object)); 164 $fields[] = id(new PhabricatorDividerEditField()) 165 ->setKey('update.note'); 166 } 167 168 $fields[] = id(new PhabricatorTextEditField()) 169 ->setKey(DifferentialRevisionTitleTransaction::EDITKEY) 170 ->setLabel(pht('Title')) 171 ->setIsRequired(true) 172 ->setTransactionType( 173 DifferentialRevisionTitleTransaction::TRANSACTIONTYPE) 174 ->setDescription(pht('The title of the revision.')) 175 ->setConduitDescription(pht('Retitle the revision.')) 176 ->setConduitTypeDescription(pht('New revision title.')) 177 ->setValue($object->getTitle()); 178 179 $author_field = id(new PhabricatorDatasourceEditField()) 180 ->setKey(DifferentialRevisionAuthorTransaction::EDITKEY) 181 ->setLabel(pht('Author')) 182 ->setDatasource(new PhabricatorPeopleDatasource()) 183 ->setTransactionType( 184 DifferentialRevisionAuthorTransaction::TRANSACTIONTYPE) 185 ->setDescription(pht('Make someone else the author of this revision.')) 186 ->setConduitDescription( 187 pht('Make another user the author of this revision.')) 188 ->setConduitTypeDescription(pht('New author.')) 189 ->setSingleValue($object->getAuthorPHID()); 190 191 // Don't show the "Author" field when creating a revision using the web 192 // workflow, since it adds more noise than signal to this workflow. 193 if ($is_create) { 194 $author_field->setIsHidden(true); 195 } 196 197 // Only show the "Change Author" comment action to the current revision 198 // author. Other users can use "Edit Revision", it's just very unlikely 199 // that they're interested in this action. 200 if ($viewer->getPHID() === $object->getAuthorPHID()) { 201 $author_field->setCommentActionLabel(pht('Change Author')); 202 } 203 204 $fields[] = $author_field; 205 206 $fields[] = id(new PhabricatorRemarkupEditField()) 207 ->setKey(DifferentialRevisionSummaryTransaction::EDITKEY) 208 ->setLabel(pht('Summary')) 209 ->setTransactionType( 210 DifferentialRevisionSummaryTransaction::TRANSACTIONTYPE) 211 ->setDescription(pht('The summary of the revision.')) 212 ->setConduitDescription(pht('Change the revision summary.')) 213 ->setConduitTypeDescription(pht('New revision summary.')) 214 ->setValue($object->getSummary()); 215 216 if ($plan_enabled) { 217 $fields[] = id(new PhabricatorRemarkupEditField()) 218 ->setKey(DifferentialRevisionTestPlanTransaction::EDITKEY) 219 ->setLabel(pht('Test Plan')) 220 ->setIsRequired($plan_required) 221 ->setTransactionType( 222 DifferentialRevisionTestPlanTransaction::TRANSACTIONTYPE) 223 ->setDescription( 224 pht('Actions performed to verify the behavior of the change.')) 225 ->setConduitDescription(pht('Update the revision test plan.')) 226 ->setConduitTypeDescription(pht('New test plan.')) 227 ->setValue($object->getTestPlan()); 228 } 229 230 $fields[] = id(new PhabricatorDatasourceEditField()) 231 ->setKey(DifferentialRevisionReviewersTransaction::EDITKEY) 232 ->setLabel(pht('Reviewers')) 233 ->setDatasource(new DifferentialReviewerDatasource()) 234 ->setUseEdgeTransactions(true) 235 ->setTransactionType( 236 DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE) 237 ->setCommentActionLabel(pht('Change Reviewers')) 238 ->setDescription(pht('Reviewers for this revision.')) 239 ->setConduitDescription(pht('Change the reviewers for this revision.')) 240 ->setConduitTypeDescription(pht('New reviewers.')) 241 ->setValue($object->getReviewerPHIDsForEdit()); 242 243 // Prefill Repository for example when coming from "Attach To". 244 $repository_phid = $object->getRepositoryPHID(); 245 if ($is_create && !$repository_phid && $diff) { 246 $repository_phid = $diff->getRepositoryPHID(); 247 } 248 249 $fields[] = id(new PhabricatorDatasourceEditField()) 250 ->setKey('repositoryPHID') 251 ->setLabel(pht('Repository')) 252 ->setDatasource(new DiffusionRepositoryDatasource()) 253 ->setTransactionType( 254 DifferentialRevisionRepositoryTransaction::TRANSACTIONTYPE) 255 ->setDescription(pht('The repository the revision belongs to.')) 256 ->setConduitDescription(pht('Change the repository for this revision.')) 257 ->setConduitTypeDescription(pht('New repository.')) 258 ->setSingleValue($repository_phid); 259 260 // This is a little flimsy, but allows "Maniphest Tasks: ..." to continue 261 // working properly in commit messages until we fully sort out T5873. 262 $fields[] = id(new PhabricatorHandlesEditField()) 263 ->setKey('tasks') 264 ->setUseEdgeTransactions(true) 265 ->setIsFormField(false) 266 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 267 ->setMetadataValue( 268 'edge:type', 269 DifferentialRevisionHasTaskEdgeType::EDGECONST) 270 ->setDescription(pht('Tasks associated with this revision.')) 271 ->setConduitDescription(pht('Change associated tasks.')) 272 ->setConduitTypeDescription(pht('List of tasks.')) 273 ->setValue(array()); 274 275 $fields[] = id(new PhabricatorHandlesEditField()) 276 ->setKey('parents') 277 ->setUseEdgeTransactions(true) 278 ->setIsFormField(false) 279 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 280 ->setMetadataValue( 281 'edge:type', 282 DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST) 283 ->setDescription(pht('Parent revisions of this revision.')) 284 ->setConduitDescription(pht('Change associated parent revisions.')) 285 ->setConduitTypeDescription(pht('List of revisions.')) 286 ->setValue(array()); 287 288 $fields[] = id(new PhabricatorHandlesEditField()) 289 ->setKey('children') 290 ->setUseEdgeTransactions(true) 291 ->setIsFormField(false) 292 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 293 ->setMetadataValue( 294 'edge:type', 295 DifferentialRevisionDependedOnByRevisionEdgeType::EDGECONST) 296 ->setDescription(pht('Child revisions of this revision.')) 297 ->setConduitDescription(pht('Change associated child revisions.')) 298 ->setConduitTypeDescription(pht('List of revisions.')) 299 ->setValue(array()); 300 301 $actions = DifferentialRevisionActionTransaction::loadAllActions(); 302 $actions = msortv($actions, 'getRevisionActionOrderVector'); 303 304 foreach ($actions as $key => $action) { 305 $fields[] = $action->newEditField($object, $viewer); 306 } 307 308 $fields[] = id(new PhabricatorBoolEditField()) 309 ->setKey('draft') 310 ->setLabel(pht('Hold as Draft')) 311 ->setIsFormField(false) 312 ->setOptions( 313 pht('Autosubmit Once Builds Finish'), 314 pht('Hold as Draft')) 315 ->setTransactionType( 316 DifferentialRevisionHoldDraftTransaction::TRANSACTIONTYPE) 317 ->setDescription(pht('Hold revision as draft.')) 318 ->setConduitDescription( 319 pht( 320 'Change autosubmission from draft state after builds finish.')) 321 ->setConduitTypeDescription(pht('New "Hold as Draft" setting.')) 322 ->setValue($object->getHoldAsDraft()); 323 324 return $fields; 325 } 326 327 private function isCustomFieldEnabled(DifferentialRevision $revision, $key) { 328 $field_list = PhabricatorCustomField::getObjectFields( 329 $revision, 330 PhabricatorCustomField::ROLE_VIEW); 331 332 $fields = $field_list->getFields(); 333 return isset($fields[$key]); 334 } 335 336 protected function newAutomaticCommentTransactions($object) { 337 $viewer = $this->getViewer(); 338 339 $editor = $object->getApplicationTransactionEditor() 340 ->setActor($viewer); 341 342 $xactions = $editor->newAutomaticInlineTransactions( 343 $object, 344 DifferentialTransaction::TYPE_INLINE, 345 new DifferentialDiffInlineCommentQuery()); 346 347 return $xactions; 348 } 349 350 protected function newCommentPreviewContent($object, array $xactions) { 351 $viewer = $this->getViewer(); 352 $type_inline = DifferentialTransaction::TYPE_INLINE; 353 354 $inlines = array(); 355 foreach ($xactions as $xaction) { 356 if ($xaction->getTransactionType() === $type_inline) { 357 $inlines[] = $xaction->getComment(); 358 } 359 } 360 361 $content = array(); 362 363 if ($inlines) { 364 // Reload inlines to get inline context. 365 $inlines = id(new DifferentialDiffInlineCommentQuery()) 366 ->setViewer($viewer) 367 ->withIDs(mpull($inlines, 'getID')) 368 ->needInlineContext(true) 369 ->execute(); 370 371 $inline_preview = id(new PHUIDiffInlineCommentPreviewListView()) 372 ->setViewer($viewer) 373 ->setInlineComments($inlines); 374 375 $content[] = phutil_tag( 376 'div', 377 array( 378 'id' => 'inline-comment-preview', 379 ), 380 $inline_preview); 381 } 382 383 return $content; 384 } 385 386 387}