diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 61100f848f..d40b8c6805 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -139,6 +139,7 @@ phutil_register_library_map(array(
'DifferentialAuxiliaryField' => 'applications/differential/storage/auxiliaryfield',
'DifferentialBlameRevisionFieldSpecification' => 'applications/differential/field/specification/blamerev',
'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
+ 'DifferentialCCsFieldSpecification' => 'applications/differential/field/specification/ccs',
'DifferentialChangeType' => 'applications/differential/constants/changetype',
'DifferentialChangeset' => 'applications/differential/storage/changeset',
'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
@@ -180,6 +181,7 @@ phutil_register_library_map(array(
'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/lines',
+ 'DifferentialLintFieldSpecification' => 'applications/differential/field/specification/lint',
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
'DifferentialMail' => 'applications/differential/mail/base',
'DifferentialManiphestTasksFieldSpecification' => 'applications/differential/field/specification/maniphesttasks',
@@ -189,6 +191,7 @@ phutil_register_library_map(array(
'DifferentialReplyHandler' => 'applications/differential/replyhandler',
'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/revertplan',
'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
+ 'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/reviewers',
'DifferentialRevision' => 'applications/differential/storage/revision',
'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
@@ -200,10 +203,12 @@ phutil_register_library_map(array(
'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
+ 'DifferentialRevisionStatusFieldSpecification' => 'applications/differential/field/specification/revisionstatus',
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
'DifferentialTasksAttacher' => 'applications/differential/tasks',
+ 'DifferentialUnitFieldSpecification' => 'applications/differential/field/specification/unit',
'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult',
'DifferentialViewTime' => 'applications/differential/storage/viewtime',
@@ -792,6 +797,7 @@ phutil_register_library_map(array(
'DifferentialAuxiliaryField' => 'DifferentialDAO',
'DifferentialBlameRevisionFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
+ 'DifferentialCCsFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialChangeset' => 'DifferentialDAO',
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetListView' => 'AphrontView',
@@ -820,6 +826,7 @@ phutil_register_library_map(array(
'DifferentialInlineCommentPreviewController' => 'DifferentialController',
'DifferentialInlineCommentView' => 'AphrontView',
'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification',
+ 'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
'DifferentialPathFieldSpecification' => 'DifferentialFieldSpecification',
@@ -827,15 +834,18 @@ phutil_register_library_map(array(
'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler',
'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialReviewRequestMail' => 'DifferentialMail',
+ 'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRevision' => 'DifferentialDAO',
'DifferentialRevisionCommentListView' => 'AphrontView',
'DifferentialRevisionCommentView' => 'AphrontView',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionListController' => 'DifferentialController',
+ 'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
'DifferentialRevisionViewController' => 'DifferentialController',
'DifferentialSubscribeController' => 'DifferentialController',
+ 'DifferentialUnitFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialViewTime' => 'DifferentialDAO',
'DiffusionBranchTableView' => 'DiffusionView',
'DiffusionBrowseController' => 'DiffusionController',
diff --git a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
index accf29754a..a9dc09b4a7 100644
--- a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
+++ b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
@@ -58,10 +58,7 @@ class DifferentialRevisionViewController extends DifferentialController {
$diff_vs = null;
}
- $aux_fields = $this->loadAuxiliaryFields($revision);
- foreach ($aux_fields as $aux_field) {
- $aux_field->setDiff($target);
- }
+ $aux_fields = $this->loadAuxiliaryFields($revision, $target);
list($changesets, $vs_map, $rendering_references) =
$this->loadChangesetsAndVsMap($diffs, $diff_vs, $target);
@@ -156,47 +153,31 @@ class DifferentialRevisionViewController extends DifferentialController {
$visible_changesets = $changesets;
}
- $diff_properties = id(new DifferentialDiffProperty())->loadAllWhere(
- 'diffID = %d AND name IN (%Ls)',
- $target->getID(),
- array(
- 'arc:lint',
- 'arc:unit',
- ));
- $diff_properties = mpull($diff_properties, 'getData', 'getName');
-
$revision_detail = new DifferentialRevisionDetailView();
$revision_detail->setRevision($revision);
$revision_detail->setAuxiliaryFields($aux_fields);
+ $actions = $this->getRevisionActions($revision);
+
$custom_renderer_class = PhabricatorEnv::getEnvConfig(
'differential.revision-custom-detail-renderer');
if ($custom_renderer_class) {
+
+ // TODO: Either deprecate generateProperties() or build a better version
+ // of the action links and deprecate the whole class. Custom fields
+ // now provide a much more powerful version of generateProperties().
+
PhutilSymbolLoader::loadClass($custom_renderer_class);
$custom_renderer =
newv($custom_renderer_class, array());
- } else {
- $custom_renderer = null;
- }
+ $properties = $custom_renderer->generateProperties($revision, $target);
+ $revision_detail->setProperties($properties);
- $properties = $this->getRevisionProperties(
- $revision,
- $target,
- $handles,
- $diff_properties);
- if ($custom_renderer) {
- $properties = array_merge(
- $properties,
- $custom_renderer->generateProperties($revision, $target));
- }
-
- $revision_detail->setProperties($properties);
-
- $actions = $this->getRevisionActions($revision);
- if ($custom_renderer) {
$actions = array_merge(
$actions,
$custom_renderer->generateActionLinks($revision, $target));
+ } else {
+ $revision_detail->setProperties(array());
}
$whitespace = $request->getStr(
@@ -307,143 +288,6 @@ class DifferentialRevisionViewController extends DifferentialController {
return $comments;
}
- private function getRevisionProperties(
- DifferentialRevision $revision,
- DifferentialDiff $diff,
- array $handles,
- array $diff_properties) {
-
- $properties = array();
-
- $status = $revision->getStatus();
- $next_step = null;
- if ($status == DifferentialRevisionStatus::ACCEPTED) {
- switch ($diff->getSourceControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $next_step = 'arc amend --revision '.$revision->getID();
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $next_step = 'arc commit --revision '.$revision->getID();
- break;
- }
- if ($next_step) {
- $next_step =
- ' · '.
- 'Next step: '.phutil_escape_html($next_step).'';
- }
- }
- $status = DifferentialRevisionStatus::getNameForRevisionStatus($status);
- $properties['Revision Status'] = ''.$status.''.$next_step;
-
- $properties['Reviewers'] = $this->renderHandleLinkList(
- array_select_keys(
- $handles,
- $revision->getReviewers()));
-
- $properties['CCs'] = $this->renderHandleLinkList(
- array_select_keys(
- $handles,
- $revision->getCCPHIDs()));
-
- $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
- $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
- $ldata = idx($diff_properties, 'arc:lint');
- $ltail = null;
- if ($ldata) {
- $ldata = igroup($ldata, 'path');
- $lint_messages = array();
- foreach ($ldata as $path => $messages) {
- $message_markup = array();
- foreach ($messages as $message) {
- $path = idx($message, 'path');
- $line = idx($message, 'line');
-
- $code = idx($message, 'code');
- $severity = idx($message, 'severity');
-
- $name = idx($message, 'name');
- $description = idx($message, 'description');
-
- $message_markup[] =
- '
'.
- ''.
- phutil_escape_html(ucwords($severity)).
- ''.
- ' '.
- '('.phutil_escape_html($code).') '.
- phutil_escape_html($name).
- ' at line '.phutil_escape_html($line).
- ''.phutil_escape_html($description).'
'.
- '';
- }
- $lint_messages[] =
- ''.
- 'Lint for '.phutil_escape_html($path).''.
- ''.implode("\n", $message_markup).'
'.
- '';
- }
- $ltail =
- ''.
- '
'.
- implode("\n", $lint_messages).
- '
'.
- '
';
- }
-
- $properties['Lint'] = $lstar.' '.$lmsg.$ltail;
-
- $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
- $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
-
- $postponed_count = 0;
- $udata = idx($diff_properties, 'arc:unit');
- $utail = null;
- if ($udata) {
- $unit_messages = array();
- foreach ($udata as $test) {
- $name = phutil_escape_html(idx($test, 'name'));
- $result = phutil_escape_html(idx($test, 'result'));
-
- if ($result != DifferentialUnitTestResult::RESULT_POSTPONED &&
- $result != DifferentialUnitTestResult::RESULT_PASS) {
- $userdata = phutil_escape_html(idx($test, 'userdata'));
- if (strlen($userdata) > 256) {
- $userdata = substr($userdata, 0, 256).'...';
- }
- $userdata = str_replace("\n", '
', $userdata);
- $unit_messages[] =
- ''.
- ''.$name.' | '.
- ''.
- ' '.
- strtoupper($result).
- ' '.
- ' | '.
- ''.$userdata.' | '.
- '
';
-
- $utail =
- ''.
- '
'.
- implode("\n", $unit_messages).
- '
'.
- '
';
- } else if ($result == DifferentialUnitTestResult::RESULT_POSTPONED) {
- $postponed_count++;
- }
- }
- }
-
- if ($postponed_count > 0 &&
- $diff->getUnitStatus() == DifferentialUnitStatus::UNIT_POSTPONED) {
- $umsg = $postponed_count.' '.$umsg;
- }
-
- $properties['Unit'] = $ustar.' '.$umsg.$utail;
-
- return $properties;
- }
-
private function getRevisionActions(DifferentialRevision $revision) {
$viewer_phid = $this->getRequest()->getUser()->getPHID();
$viewer_is_owner = ($revision->getAuthorPHID() == $viewer_phid);
@@ -512,14 +356,6 @@ class DifferentialRevisionViewController extends DifferentialController {
return $links;
}
-
- private function renderHandleLinkList(array $list) {
- if (empty($list)) {
- return 'None';
- }
- return implode(', ', mpull($list, 'renderLink'));
- }
-
private function getRevisionCommentActions(DifferentialRevision $revision) {
$actions = array(
@@ -674,7 +510,9 @@ class DifferentialRevisionViewController extends DifferentialController {
->replace();
}
- private function loadAuxiliaryFields(DifferentialRevision $revision) {
+ private function loadAuxiliaryFields(
+ DifferentialRevision $revision,
+ DifferentialDiff $diff) {
$aux_fields = DifferentialFieldSelector::newSelector()
->getFieldSpecifications();
foreach ($aux_fields as $key => $aux_field) {
@@ -683,9 +521,42 @@ class DifferentialRevisionViewController extends DifferentialController {
}
}
- return DifferentialAuxiliaryField::loadFromStorage(
+ $aux_fields = DifferentialAuxiliaryField::loadFromStorage(
$revision,
$aux_fields);
+
+ $aux_props = array();
+ foreach ($aux_fields as $key => $aux_field) {
+ $aux_field->setDiff($diff);
+ $aux_props[$key] = $aux_field->getRequiredDiffProperties();
+ }
+
+ $required_properties = array_mergev($aux_props);
+ $property_map = array();
+ if ($required_properties) {
+ $properties = id(new DifferentialDiffProperty())->loadAllWhere(
+ 'diffID = %d AND name IN (%Ls)',
+ $diff->getID(),
+ $required_properties);
+ $property_map = mpull($properties, 'getData', 'getName');
+ }
+
+ foreach ($aux_fields as $key => $aux_field) {
+ // Give each field only the properties it specifically required, and
+ // set 'null' for each requested key which we didn't actually load a
+ // value for (otherwise, getDiffProperty() will throw).
+ if ($aux_props[$key]) {
+ $props = array_select_keys($property_map, $aux_props[$key]) +
+ array_fill_keys($aux_props[$key], null);
+ } else {
+ $props = array();
+ }
+
+ $aux_field->setDiffProperties($props);
+ }
+
+ return $aux_fields;
}
+
}
diff --git a/src/applications/differential/controller/revisionview/__init__.php b/src/applications/differential/controller/revisionview/__init__.php
index 042008c08e..a7809f0195 100644
--- a/src/applications/differential/controller/revisionview/__init__.php
+++ b/src/applications/differential/controller/revisionview/__init__.php
@@ -9,8 +9,6 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/differential/constants/action');
phutil_require_module('phabricator', 'applications/differential/constants/revisionstatus');
-phutil_require_module('phabricator', 'applications/differential/constants/unitstatus');
-phutil_require_module('phabricator', 'applications/differential/constants/unittestresult');
phutil_require_module('phabricator', 'applications/differential/controller/base');
phutil_require_module('phabricator', 'applications/differential/field/selector/base');
phutil_require_module('phabricator', 'applications/differential/parser/changeset');
@@ -30,7 +28,6 @@ phutil_require_module('phabricator', 'applications/differential/view/revisiondet
phutil_require_module('phabricator', 'applications/differential/view/revisionupdatehistory');
phutil_require_module('phabricator', 'applications/draft/storage/draft');
phutil_require_module('phabricator', 'applications/phid/handle/data');
-phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'infrastructure/javelin/api');
diff --git a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php
index 3f56616304..6611492e51 100644
--- a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php
+++ b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php
@@ -165,12 +165,25 @@ class DifferentialRevisionEditor {
if ($revision->getAuthorPHID() === null) {
$revision->setAuthorPHID($this->getActorPHID());
}
-
+ if ($revision->getRevertPlan() === null) {
+ $revision->setRevertPlan('');
+ }
+ if ($revision->getBlameRevision() === null) {
+ $revision->setBlameRevision('');
+ }
+ if ($revision->getSummary() === null) {
+ $revision->setSummary('');
+ }
+ if ($revision->getTestPlan() === null) {
+ $revision->setTestPlan('');
+ }
$revision->save();
}
$revision->loadRelationships();
+ $this->willWriteRevision();
+
if ($this->reviewers === null) {
$this->reviewers = $revision->getReviewers();
}
@@ -368,6 +381,8 @@ class DifferentialRevisionEditor {
$revision->save();
+ $this->didWriteRevision();
+
$event_data = array(
'revision_id' => $revision->getID(),
'revision_phid' => $revision->getPHID(),
@@ -689,6 +704,17 @@ class DifferentialRevisionEditor {
}
}
+ private function willWriteRevision() {
+ foreach ($this->auxiliaryFields as $aux_field) {
+ $aux_field->willWriteRevision($this);
+ }
+ }
+
+ private function didWriteRevision() {
+ foreach ($this->auxiliaryFields as $aux_field) {
+ $aux_field->didWriteRevision($this);
+ }
+ }
}
diff --git a/src/applications/differential/field/selector/default/DifferentialDefaultFieldSelector.php b/src/applications/differential/field/selector/default/DifferentialDefaultFieldSelector.php
index 5c31d0fb02..0c9380c8ac 100644
--- a/src/applications/differential/field/selector/default/DifferentialDefaultFieldSelector.php
+++ b/src/applications/differential/field/selector/default/DifferentialDefaultFieldSelector.php
@@ -21,10 +21,15 @@ final class DifferentialDefaultFieldSelector
public function getFieldSpecifications() {
return array(
+ new DifferentialRevisionStatusFieldSpecification(),
new DifferentialAuthorFieldSpecification(),
+ new DifferentialReviewersFieldSpecification(),
+ new DifferentialCCsFieldSpecification(),
+ new DifferentialUnitFieldSpecification(),
+ new DifferentialLintFieldSpecification(),
+ new DifferentialCommitsFieldSpecification(),
new DifferentialDependenciesFieldSpecification(),
new DifferentialManiphestTasksFieldSpecification(),
- new DifferentialCommitsFieldSpecification(),
new DifferentialHostFieldSpecification(),
new DifferentialPathFieldSpecification(),
new DifferentialLinesFieldSpecification(),
diff --git a/src/applications/differential/field/selector/default/__init__.php b/src/applications/differential/field/selector/default/__init__.php
index b8cd112fb7..85864635b0 100644
--- a/src/applications/differential/field/selector/default/__init__.php
+++ b/src/applications/differential/field/selector/default/__init__.php
@@ -10,13 +10,18 @@ phutil_require_module('phabricator', 'applications/differential/field/selector/b
phutil_require_module('phabricator', 'applications/differential/field/specification/applypatch');
phutil_require_module('phabricator', 'applications/differential/field/specification/arcanistproject');
phutil_require_module('phabricator', 'applications/differential/field/specification/author');
+phutil_require_module('phabricator', 'applications/differential/field/specification/ccs');
phutil_require_module('phabricator', 'applications/differential/field/specification/commits');
phutil_require_module('phabricator', 'applications/differential/field/specification/dependencies');
phutil_require_module('phabricator', 'applications/differential/field/specification/exportpatch');
phutil_require_module('phabricator', 'applications/differential/field/specification/host');
phutil_require_module('phabricator', 'applications/differential/field/specification/lines');
+phutil_require_module('phabricator', 'applications/differential/field/specification/lint');
phutil_require_module('phabricator', 'applications/differential/field/specification/maniphesttasks');
phutil_require_module('phabricator', 'applications/differential/field/specification/path');
+phutil_require_module('phabricator', 'applications/differential/field/specification/reviewers');
+phutil_require_module('phabricator', 'applications/differential/field/specification/revisionstatus');
+phutil_require_module('phabricator', 'applications/differential/field/specification/unit');
phutil_require_source('DifferentialDefaultFieldSelector.php');
diff --git a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
index 4e87173a1e..ae036cfeb4 100644
--- a/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
+++ b/src/applications/differential/field/specification/base/DifferentialFieldSpecification.php
@@ -28,7 +28,7 @@
* @task edit Extending the Revision Edit Interface
* @task view Extending the Revision View Interface
* @task conduit Extending the Conduit View Interface
- * @task handles Loading Handles
+ * @task load Loading Additional Data
* @task context Contextual Data
*/
abstract class DifferentialFieldSpecification {
@@ -36,6 +36,7 @@ abstract class DifferentialFieldSpecification {
private $revision;
private $diff;
private $handles;
+ private $diffProperties;
/* -( Storage )------------------------------------------------------------ */
@@ -174,11 +175,34 @@ abstract class DifferentialFieldSpecification {
return;
}
+ /**
+ * @task edit
+ */
+ public function willWriteRevision(DifferentialRevisionEditor $editor) {
+ return;
+ }
+
+ /**
+ * @task edit
+ */
+ public function didWriteRevision(DifferentialRevisionEditor $editor) {
+ return;
+ }
+
/* -( Extending the Revision View Interface )------------------------------ */
/**
+ * Determine if this field should appear on the revision detail view
+ * interface. One use of this interface is to add purely informational
+ * fields to the revision view, without any sort of backing storage.
+ *
+ * If you return true from this method, you must implement the methods
+ * @{method:renderLabelForRevisionView} and
+ * @{method:renderValueForRevisionView}.
+ *
+ * @return bool True if this field should appear when viewing a revision.
* @task view
*/
public function shouldAppearOnRevisionView() {
@@ -187,6 +211,13 @@ abstract class DifferentialFieldSpecification {
/**
+ * Return a string field label which will appear in the revision detail
+ * table.
+ *
+ * You must implement this method if you return true from
+ * @{method:shouldAppearOnRevisionView}.
+ *
+ * @return string Label for field in revision detail view.
* @task view
*/
public function renderLabelForRevisionView() {
@@ -195,6 +226,16 @@ abstract class DifferentialFieldSpecification {
/**
+ * Return a markup block representing the field for the revision detail
+ * view. Note that you can return null to suppress display (for instance,
+ * if the field shows related objects of some type and the revision doesn't
+ * have any related objects).
+ *
+ * You must implement this method if you return true from
+ * @{method:shouldAppearOnRevisionView}.
+ *
+ * @return string|null Display markup for field value, or null to suppress
+ * field rendering.
* @task view
*/
public function renderValueForRevisionView() {
@@ -231,7 +272,7 @@ abstract class DifferentialFieldSpecification {
}
-/* -( Loading Handles )---------------------------------------------------- */
+/* -( Loading Additional Data )-------------------------------------------- */
/**
@@ -248,7 +289,7 @@ abstract class DifferentialFieldSpecification {
* You can later retrieve these handles by calling @{method:getHandle}.
*
* @return list List of PHIDs to load handles for.
- * @task handles
+ * @task load
*/
protected function getRequiredHandlePHIDs() {
return array();
@@ -263,7 +304,7 @@ abstract class DifferentialFieldSpecification {
* need.
*
* @return list List of PHIDs to load handles for.
- * @task handles
+ * @task load
*/
public function getRequiredHandlePHIDsForRevisionView() {
return $this->getRequiredHandlePHIDs();
@@ -278,13 +319,24 @@ abstract class DifferentialFieldSpecification {
* need.
*
* @return list List of PHIDs to load handles for.
- * @task handles
+ * @task load
*/
public function getRequiredHandlePHIDsForEdit() {
return $this->getRequiredHandlePHIDs();
}
+ /**
+ * Specify which diff properties this field needs to load.
+ *
+ * @return list List of diff property keys this field requires.
+ * @task load
+ */
+ public function getRequiredDiffProperties() {
+ return array();
+ }
+
+
/* -( Contextual Data )---------------------------------------------------- */
@@ -312,6 +364,14 @@ abstract class DifferentialFieldSpecification {
return $this;
}
+ /**
+ * @task context
+ */
+ final public function setDiffProperties(array $diff_properties) {
+ $this->diffProperties = $diff_properties;
+ return $this;
+ }
+
/**
* @task context
*/
@@ -341,6 +401,9 @@ abstract class DifferentialFieldSpecification {
* @task context
*/
final protected function getHandle($phid) {
+ if ($this->handles === null) {
+ throw new DifferentialFieldDataNotAvailableException($this);
+ }
if (empty($this->handles[$phid])) {
$class = get_class($this);
throw new Exception(
@@ -351,4 +414,30 @@ abstract class DifferentialFieldSpecification {
return $this->handles[$phid];
}
+ /**
+ * Get a diff property which this field previously requested by returning
+ * the key from @{method:getRequiredDiffProperties}.
+ *
+ * @param string Diff property key.
+ * @return string|null Diff property, or null if the property does not have
+ * a value.
+ * @task context
+ */
+ final public function getDiffProperty($key) {
+ if ($this->diffProperties === null) {
+ // This will be set to some (possibly empty) array if we've loaded
+ // properties, so null means diff properties aren't available in this
+ // context.
+ throw new DifferentialFieldDataNotAvailableException($this);
+ }
+ if (!array_key_exists($key, $this->diffProperties)) {
+ $class = get_class($this);
+ throw new Exception(
+ "A differential field (of class '{$class}') is attempting to retrieve ".
+ "a diff property ('{$key}') which it did not request. Return all ".
+ "diff property keys you need from getRequiredDiffProperties().");
+ }
+ return $this->diffProperties[$key];
+ }
+
}
diff --git a/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php b/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php
new file mode 100644
index 0000000000..ed57ab83fc
--- /dev/null
+++ b/src/applications/differential/field/specification/ccs/DifferentialCCsFieldSpecification.php
@@ -0,0 +1,53 @@
+getCCPHIDs();
+ }
+
+ public function renderLabelForRevisionView() {
+ return 'CCs:';
+ }
+
+ public function renderValueForRevisionView() {
+ $cc_phids = $this->getCCPHIDs();
+ if (!$cc_phids) {
+ return 'None';
+ }
+
+ $links = array();
+ foreach ($cc_phids as $cc_phid) {
+ $links[] = $this->getHandle($cc_phid)->renderLink();
+ }
+
+ return implode(', ', $links);
+ }
+
+ private function getCCPHIDs() {
+ $revision = $this->getRevision();
+ return $revision->getCCPHIDs();
+ }
+
+}
diff --git a/src/applications/differential/field/specification/ccs/__init__.php b/src/applications/differential/field/specification/ccs/__init__.php
new file mode 100644
index 0000000000..f7e1685565
--- /dev/null
+++ b/src/applications/differential/field/specification/ccs/__init__.php
@@ -0,0 +1,12 @@
+getDiff();
+
+ $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
+ $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
+ $ldata = $this->getDiffProperty('arc:lint');
+ $ltail = null;
+ if ($ldata) {
+ $ldata = igroup($ldata, 'path');
+ $lint_messages = array();
+ foreach ($ldata as $path => $messages) {
+ $message_markup = array();
+ foreach ($messages as $message) {
+ $path = idx($message, 'path');
+ $line = idx($message, 'line');
+
+ $code = idx($message, 'code');
+ $severity = idx($message, 'severity');
+
+ $name = idx($message, 'name');
+ $description = idx($message, 'description');
+
+ $message_markup[] =
+ ''.
+ ''.
+ phutil_escape_html(ucwords($severity)).
+ ''.
+ ' '.
+ '('.phutil_escape_html($code).') '.
+ phutil_escape_html($name).
+ ' at line '.phutil_escape_html($line).
+ ''.phutil_escape_html($description).'
'.
+ '';
+ }
+ $lint_messages[] =
+ ''.
+ 'Lint for '.phutil_escape_html($path).''.
+ ''.implode("\n", $message_markup).'
'.
+ '';
+ }
+ $ltail =
+ ''.
+ '
'.
+ implode("\n", $lint_messages).
+ '
'.
+ '
';
+ }
+
+ return $lstar.' '.$lmsg.$ltail;
+ }
+}
diff --git a/src/applications/differential/field/specification/lint/__init__.php b/src/applications/differential/field/specification/lint/__init__.php
new file mode 100644
index 0000000000..0041dfe5f7
--- /dev/null
+++ b/src/applications/differential/field/specification/lint/__init__.php
@@ -0,0 +1,16 @@
+getReviewerPHIDs();
+ }
+
+ public function renderLabelForRevisionView() {
+ return 'Reviewers:';
+ }
+
+ public function renderValueForRevisionView() {
+ $reviewer_phids = $this->getReviewerPHIDs();
+ if (!$reviewer_phids) {
+ return 'None';
+ }
+
+ $links = array();
+ foreach ($reviewer_phids as $reviewer_phid) {
+ $links[] = $this->getHandle($reviewer_phid)->renderLink();
+ }
+
+ return implode(', ', $links);
+ }
+
+ private function getReviewerPHIDs() {
+ $revision = $this->getRevision();
+ return $revision->getReviewers();
+ }
+
+}
diff --git a/src/applications/differential/field/specification/reviewers/__init__.php b/src/applications/differential/field/specification/reviewers/__init__.php
new file mode 100644
index 0000000000..fb1adf0a61
--- /dev/null
+++ b/src/applications/differential/field/specification/reviewers/__init__.php
@@ -0,0 +1,12 @@
+getRevision();
+ $diff = $this->getDiff();
+
+ $status = $revision->getStatus();
+ $next_step = null;
+ if ($status == DifferentialRevisionStatus::ACCEPTED) {
+ switch ($diff->getSourceControlSystem()) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
+ $next_step = 'arc amend --revision '.$revision->getID();
+ break;
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ $next_step = 'arc commit --revision '.$revision->getID();
+ break;
+ }
+ if ($next_step) {
+ $next_step =
+ ' · '.
+ 'Next step: '.phutil_escape_html($next_step).'';
+ }
+ }
+ $status = DifferentialRevisionStatus::getNameForRevisionStatus($status);
+ return ''.$status.''.$next_step;
+ }
+
+}
diff --git a/src/applications/differential/field/specification/revisionstatus/__init__.php b/src/applications/differential/field/specification/revisionstatus/__init__.php
new file mode 100644
index 0000000000..c8649c3340
--- /dev/null
+++ b/src/applications/differential/field/specification/revisionstatus/__init__.php
@@ -0,0 +1,16 @@
+getDiff();
+
+ $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
+ $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
+
+ $postponed_count = 0;
+ $udata = $this->getDiffProperty('arc:unit');
+ $utail = null;
+
+ if ($udata) {
+ $unit_messages = array();
+ foreach ($udata as $test) {
+ $name = phutil_escape_html(idx($test, 'name'));
+ $result = phutil_escape_html(idx($test, 'result'));
+
+ if ($result != DifferentialUnitTestResult::RESULT_POSTPONED &&
+ $result != DifferentialUnitTestResult::RESULT_PASS) {
+ $userdata = phutil_escape_html(idx($test, 'userdata'));
+ if (strlen($userdata) > 256) {
+ $userdata = substr($userdata, 0, 256).'...';
+ }
+ $userdata = str_replace("\n", '
', $userdata);
+ $unit_messages[] =
+ ''.
+ ''.$name.' | '.
+ ''.
+ ' '.
+ strtoupper($result).
+ ' '.
+ ' | '.
+ ''.$userdata.' | '.
+ '
';
+
+ $utail =
+ ''.
+ '
'.
+ implode("\n", $unit_messages).
+ '
'.
+ '
';
+ } else if ($result == DifferentialUnitTestResult::RESULT_POSTPONED) {
+ $postponed_count++;
+ }
+ }
+ }
+
+ if ($postponed_count > 0 &&
+ $diff->getUnitStatus() == DifferentialUnitStatus::UNIT_POSTPONED) {
+ $umsg = $postponed_count.' '.$umsg;
+ }
+
+ return $ustar.' '.$umsg.$utail;
+ }
+
+}
diff --git a/src/applications/differential/field/specification/unit/__init__.php b/src/applications/differential/field/specification/unit/__init__.php
new file mode 100644
index 0000000000..73b0a4571c
--- /dev/null
+++ b/src/applications/differential/field/specification/unit/__init__.php
@@ -0,0 +1,18 @@
+