diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1a655fd589..688bbe2e3d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -133,6 +133,7 @@ phutil_register_library_map(array( 'DatabaseConfigurationProvider' => 'applications/base/storage/configuration', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', + 'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/applypatch', 'DifferentialAuxiliaryField' => 'applications/differential/storage/auxiliaryfield', 'DifferentialBlameRevisionFieldSpecification' => 'applications/differential/field/specification/blamerev', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', @@ -162,18 +163,23 @@ phutil_register_library_map(array( 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialExceptionMail' => 'applications/differential/mail/exception', + 'DifferentialExportPatchFieldSpecification' => 'applications/differential/field/specification/exportpatch', + 'DifferentialFieldDataNotAvailableException' => 'applications/differential/field/exception/notavailable', 'DifferentialFieldSelector' => 'applications/differential/field/selector/base', 'DifferentialFieldSpecification' => 'applications/differential/field/specification/base', 'DifferentialFieldSpecificationIncompleteException' => 'applications/differential/field/exception/incomplete', 'DifferentialFieldValidationException' => 'applications/differential/field/exception/validation', + 'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/host', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview', 'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment', + 'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/lines', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', + 'DifferentialPathFieldSpecification' => 'applications/differential/field/specification/path', 'DifferentialPrimaryPaneView' => 'applications/differential/view/primarypane', 'DifferentialReplyHandler' => 'applications/differential/replyhandler', 'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/revertplan', @@ -775,6 +781,7 @@ phutil_register_library_map(array( 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DifferentialAddCommentView' => 'AphrontView', + 'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuxiliaryField' => 'DifferentialDAO', 'DifferentialBlameRevisionFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', @@ -796,12 +803,16 @@ phutil_register_library_map(array( 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialExceptionMail' => 'DifferentialMail', + 'DifferentialExportPatchFieldSpecification' => 'DifferentialFieldSpecification', + 'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialInlineComment' => 'DifferentialDAO', 'DifferentialInlineCommentEditController' => 'DifferentialController', 'DifferentialInlineCommentPreviewController' => 'DifferentialController', 'DifferentialInlineCommentView' => 'AphrontView', + 'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', + 'DifferentialPathFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialPrimaryPaneView' => 'AphrontView', 'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler', 'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification', diff --git a/src/applications/conduit/method/differential/getrevision/ConduitAPI_differential_getrevision_Method.php b/src/applications/conduit/method/differential/getrevision/ConduitAPI_differential_getrevision_Method.php index 35d2f09778..de5b3bef06 100644 --- a/src/applications/conduit/method/differential/getrevision/ConduitAPI_differential_getrevision_Method.php +++ b/src/applications/conduit/method/differential/getrevision/ConduitAPI_differential_getrevision_Method.php @@ -116,7 +116,7 @@ class ConduitAPI_differential_getrevision_Method extends ConduitAPIMethod { $revision, $aux_fields); - return mpull($aux_fields, 'getValueForConduit', 'getStorageKey'); + return mpull($aux_fields, 'getValueForConduit', 'getKeyForConduit'); } } diff --git a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php index eb34bfda4a..823c46b53a 100644 --- a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php @@ -43,8 +43,6 @@ class DifferentialRevisionViewController extends DifferentialController { "This revision has no diffs. Something has gone quite wrong."); } - $aux_fields = $this->loadAuxiliaryFields($revision); - $diff_vs = $request->getInt('vs'); $target = end($diffs); @@ -60,6 +58,11 @@ class DifferentialRevisionViewController extends DifferentialController { $diff_vs = null; } + $aux_fields = $this->loadAuxiliaryFields($revision); + foreach ($aux_fields as $aux_field) { + $aux_field->setDiff($target); + } + list($changesets, $vs_map, $rendering_references) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target); @@ -336,17 +339,6 @@ class DifferentialRevisionViewController extends DifferentialController { $handles, $revision->getCCPHIDs())); - $host = $diff->getSourceMachine(); - if ($host) { - $properties['Host'] = phutil_escape_html($host); - } - - $path = $diff->getSourcePath(); - if ($path) { - $branch = $diff->getBranch() ? ' ('.$diff->getBranch().')' : ''; - $properties['Path'] = phutil_escape_html("{$path} {$branch}"); - } - $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = idx($diff_properties, 'arc:lint'); @@ -474,18 +466,12 @@ class DifferentialRevisionViewController extends DifferentialController { $properties['Commits'] = implode('
', $links); } - $properties['Lines'] = number_format($diff->getLineCount()); $arcanist_phid = $diff->getArcanistProjectPHID(); if ($arcanist_phid) { $properties['Arcanist Project'] = phutil_escape_html( $handles[$arcanist_phid]->getName()); } - $properties['Apply Patch'] = - 'arc patch D'.$revision->getID().''; - $properties['Export Patch'] = - 'arc export --revision '.$revision->getID().''; - return $properties; } diff --git a/src/applications/differential/field/exception/incomplete/DifferentialFieldSpecificationIncompleteException.php b/src/applications/differential/field/exception/incomplete/DifferentialFieldSpecificationIncompleteException.php index fb96c4c93e..2d49f77d5f 100644 --- a/src/applications/differential/field/exception/incomplete/DifferentialFieldSpecificationIncompleteException.php +++ b/src/applications/differential/field/exception/incomplete/DifferentialFieldSpecificationIncompleteException.php @@ -16,7 +16,8 @@ * limitations under the License. */ -class DifferentialFieldSpecificationIncompleteException extends Exception { +final class DifferentialFieldSpecificationIncompleteException + extends Exception { public function __construct(DifferentialFieldSpecification $spec) { $key = $spec->getStorageKey(); diff --git a/src/applications/differential/field/exception/notavailable/DifferentialFieldDataNotAvailableException.php b/src/applications/differential/field/exception/notavailable/DifferentialFieldDataNotAvailableException.php new file mode 100644 index 0000000000..c5cba09267 --- /dev/null +++ b/src/applications/differential/field/exception/notavailable/DifferentialFieldDataNotAvailableException.php @@ -0,0 +1,30 @@ +getStorageKey(); + $class = get_class($spec); + + parent::__construct( + "Differential field specification for '{$key}' (of class '{$class}') is ". + "attempting to access data which is not available in this context."); + } + +} diff --git a/src/applications/differential/field/exception/notavailable/__init__.php b/src/applications/differential/field/exception/notavailable/__init__.php new file mode 100644 index 0000000000..43006619be --- /dev/null +++ b/src/applications/differential/field/exception/notavailable/__init__.php @@ -0,0 +1,10 @@ +getRevision(); + return 'arc patch D'.$revision->getID().''; + } + +} diff --git a/src/applications/differential/field/specification/applypatch/__init__.php b/src/applications/differential/field/specification/applypatch/__init__.php new file mode 100644 index 0000000000..bab891a69d --- /dev/null +++ b/src/applications/differential/field/specification/applypatch/__init__.php @@ -0,0 +1,12 @@ +value = $request->getStr('my-custom-field'); + * + * If you have some particularly complicated field, you may need to read + * more data; this is why you have access to the entire request. + * + * You must implement this if you implement @{method:shouldAppearOnEdit}. + * + * You should not perform field validation here; instead, you should implement + * @{method:validateField}. + * + * @param AphrontRequest HTTP request representing a user submitting a form + * with this field in it. + * @return this * @task edit */ public function setValueFromRequest(AphrontRequest $request) { @@ -90,6 +134,21 @@ abstract class DifferentialFieldSpecification { /** + * Build a renderable object (generally, some @{class:AphrontFormControl}) + * which can be appended to a @{class:AphrontFormView} and represents the + * interface the user sees on the "Edit Revision" screen when interacting + * with this field. + * + * For example: + * + * return id(new AphrontFormTextControl()) + * ->setLabel('Custom Field') + * ->setName('my-custom-key') + * ->setValue($this->value); + * + * You must implement this if you implement @{method:shouldAppearOnEdit}. + * + * @return AphrontView|string Something renderable. * @task edit */ public function renderEditControl() { @@ -98,10 +157,19 @@ abstract class DifferentialFieldSpecification { /** + * This method will be called after @{method:setValueFromRequest} but before + * the field is saved. It gives you an opportunity to inspect the field value + * and throw a @{class:DifferentialFieldValidationException} if there is a + * problem with the value the user has provided (for example, the value the + * user entered is not correctly formatted). + * + * By default, fields are not validated. + * + * @return void * @task edit */ public function validateField() { - throw new DifferentialFieldSpecificationIncompleteException($this); + return; } @@ -149,4 +217,54 @@ abstract class DifferentialFieldSpecification { throw new DifferentialFieldSpecificationIncompleteException($this); } + /** + * @task conduit + */ + public function getKeyForConduit() { + $key = $this->getStorageKey(); + if ($key === null) { + throw new DifferentialFieldSpecificationIncompleteException($this); + } + return $key; + } + + +/* -( Contextual Data )---------------------------------------------------- */ + + /** + * @task context + */ + final public function setRevision(DifferentialRevision $revision) { + $this->revision = $revision; + return $this; + } + + /** + * @task context + */ + final public function setDiff(DifferentialDiff $diff) { + $this->diff = $diff; + return $this; + } + + /** + * @task context + */ + final protected function getRevision() { + if (empty($this->revision)) { + throw new DifferentialFieldDataNotAvailableException($this); + } + return $this->revision; + } + + /** + * @task context + */ + final protected function getDiff() { + if (empty($this->diff)) { + throw new DifferentialFieldDataNotAvailableException($this); + } + return $this->diff; + } + } diff --git a/src/applications/differential/field/specification/base/__init__.php b/src/applications/differential/field/specification/base/__init__.php index a0f7013fe7..6dcca1a4da 100644 --- a/src/applications/differential/field/specification/base/__init__.php +++ b/src/applications/differential/field/specification/base/__init__.php @@ -7,6 +7,7 @@ phutil_require_module('phabricator', 'applications/differential/field/exception/incomplete'); +phutil_require_module('phabricator', 'applications/differential/field/exception/notavailable'); phutil_require_source('DifferentialFieldSpecification.php'); diff --git a/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php b/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php index a47b0ae429..6c877c2024 100644 --- a/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php +++ b/src/applications/differential/field/specification/blamerev/DifferentialBlameRevisionFieldSpecification.php @@ -39,7 +39,7 @@ final class DifferentialBlameRevisionFieldSpecification } public function setValueFromRequest(AphrontRequest $request) { - $this->value = $request->getStr('aux:phabricator:blame-revision'); + $this->value = $request->getStr($this->getStorageKey()); return $this; } @@ -47,7 +47,7 @@ final class DifferentialBlameRevisionFieldSpecification return id(new AphrontFormTextControl()) ->setLabel('Blame Revision') ->setCaption('Revision which broke the stuff which this change fixes.') - ->setName('aux:phabricator:blame-revision') + ->setName($this->getStorageKey()) ->setValue($this->value); } diff --git a/src/applications/differential/field/specification/exportpatch/DifferentialExportPatchFieldSpecification.php b/src/applications/differential/field/specification/exportpatch/DifferentialExportPatchFieldSpecification.php new file mode 100644 index 0000000000..7499a5ce1a --- /dev/null +++ b/src/applications/differential/field/specification/exportpatch/DifferentialExportPatchFieldSpecification.php @@ -0,0 +1,35 @@ +getRevision(); + return 'arc export --revision '.$revision->getID().''; + } + +} diff --git a/src/applications/differential/field/specification/exportpatch/__init__.php b/src/applications/differential/field/specification/exportpatch/__init__.php new file mode 100644 index 0000000000..41c1df6212 --- /dev/null +++ b/src/applications/differential/field/specification/exportpatch/__init__.php @@ -0,0 +1,12 @@ +getDiff(); + $host = $diff->getSourceMachine(); + if (!$host) { + return null; + } + return phutil_escape_html($host); + } + +} diff --git a/src/applications/differential/field/specification/host/__init__.php b/src/applications/differential/field/specification/host/__init__.php new file mode 100644 index 0000000000..e1b563b162 --- /dev/null +++ b/src/applications/differential/field/specification/host/__init__.php @@ -0,0 +1,14 @@ +getDiff(); + return phutil_escape_html(number_format($diff->getLineCount())); + } + +} diff --git a/src/applications/differential/field/specification/lines/__init__.php b/src/applications/differential/field/specification/lines/__init__.php new file mode 100644 index 0000000000..4c1bc36017 --- /dev/null +++ b/src/applications/differential/field/specification/lines/__init__.php @@ -0,0 +1,14 @@ +getDiff(); + + $path = $diff->getSourcePath(); + if (!$path) { + return null; + } + + $branch = $diff->getBranch(); + if ($branch) { + $branch = ' ('.$branch.')'; + } + + return phutil_escape_html($path.$branch); + } + +} diff --git a/src/applications/differential/field/specification/path/__init__.php b/src/applications/differential/field/specification/path/__init__.php new file mode 100644 index 0000000000..f1c24de348 --- /dev/null +++ b/src/applications/differential/field/specification/path/__init__.php @@ -0,0 +1,14 @@ +value = $request->getStr('aux:phabricator:revert-plan'); + $this->value = $request->getStr($this->getStorageKey()); return $this; } public function renderEditControl() { return id(new AphrontFormTextAreaControl()) ->setLabel('Revert Plan') - ->setName('aux:phabricator:revert-plan') + ->setName($this->getStorageKey()) ->setCaption('Special steps required to safely revert this change.') ->setValue($this->value); } diff --git a/src/applications/differential/storage/auxiliaryfield/DifferentialAuxiliaryField.php b/src/applications/differential/storage/auxiliaryfield/DifferentialAuxiliaryField.php index 643f1aa29b..5bd7d51a77 100644 --- a/src/applications/differential/storage/auxiliaryfield/DifferentialAuxiliaryField.php +++ b/src/applications/differential/storage/auxiliaryfield/DifferentialAuxiliaryField.php @@ -47,6 +47,7 @@ final class DifferentialAuxiliaryField extends DifferentialDAO { } foreach ($aux_fields as $aux_field) { + $aux_field->setRevision($revision); $key = $aux_field->getStorageKey(); if ($key) { $aux_field->setValueFromStorage(idx($field_data, $key));