diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 22beb582db..9fe7674437 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -326,6 +326,7 @@ phutil_register_library_map(array( 'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/DifferentialArcanistProjectFieldSpecification.php', 'DifferentialAsanaRepresentationField' => 'applications/differential/customfield/DifferentialAsanaRepresentationField.php', 'DifferentialAsanaRepresentationFieldSpecification' => 'applications/differential/field/specification/DifferentialAsanaRepresentationFieldSpecification.php', + 'DifferentialAuditorsField' => 'applications/differential/customfield/DifferentialAuditorsField.php', 'DifferentialAuditorsFieldSpecification' => 'applications/differential/field/specification/DifferentialAuditorsFieldSpecification.php', 'DifferentialAuthorField' => 'applications/differential/customfield/DifferentialAuthorField.php', 'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/DifferentialAuthorFieldSpecification.php', @@ -360,6 +361,7 @@ phutil_register_library_map(array( 'DifferentialCommitMessageParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCommitMessageParserTestCase.php', 'DifferentialCommitsField' => 'applications/differential/customfield/DifferentialCommitsField.php', 'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/DifferentialCommitsFieldSpecification.php', + 'DifferentialConflictsField' => 'applications/differential/customfield/DifferentialConflictsField.php', 'DifferentialConflictsFieldSpecification' => 'applications/differential/field/specification/DifferentialConflictsFieldSpecification.php', 'DifferentialController' => 'applications/differential/controller/DifferentialController.php', 'DifferentialCoreCustomField' => 'applications/differential/customfield/DifferentialCoreCustomField.php', @@ -403,6 +405,7 @@ phutil_register_library_map(array( 'DifferentialFieldValidationException' => 'applications/differential/field/exception/DifferentialFieldValidationException.php', 'DifferentialFreeformFieldSpecification' => 'applications/differential/field/specification/DifferentialFreeformFieldSpecification.php', 'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php', + 'DifferentialGitSVNIDField' => 'applications/differential/customfield/DifferentialGitSVNIDField.php', 'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/DifferentialGitSVNIDFieldSpecification.php', 'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php', 'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/DifferentialHostFieldSpecification.php', @@ -454,6 +457,7 @@ phutil_register_library_map(array( 'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php', 'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/DifferentialRevertPlanFieldSpecification.php', 'DifferentialReviewRequestMail' => 'applications/differential/mail/DifferentialReviewRequestMail.php', + 'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php', 'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/DifferentialReviewedByFieldSpecification.php', 'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php', 'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php', @@ -465,6 +469,7 @@ phutil_register_library_map(array( 'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionEditor' => 'applications/differential/editor/DifferentialRevisionEditor.php', + 'DifferentialRevisionIDField' => 'applications/differential/customfield/DifferentialRevisionIDField.php', 'DifferentialRevisionIDFieldParserTestCase' => 'applications/differential/field/specification/__tests__/DifferentialRevisionIDFieldParserTestCase.php', 'DifferentialRevisionIDFieldSpecification' => 'applications/differential/field/specification/DifferentialRevisionIDFieldSpecification.php', 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', @@ -2898,6 +2903,7 @@ phutil_register_library_map(array( 'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAsanaRepresentationField' => 'DifferentialCustomField', 'DifferentialAsanaRepresentationFieldSpecification' => 'DifferentialFieldSpecification', + 'DifferentialAuditorsField' => 'DifferentialStoredCustomField', 'DifferentialAuditorsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuthorField' => 'DifferentialCustomField', 'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification', @@ -2926,6 +2932,7 @@ phutil_register_library_map(array( 'DifferentialCommitMessageParserTestCase' => 'PhabricatorTestCase', 'DifferentialCommitsField' => 'DifferentialCustomField', 'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification', + 'DifferentialConflictsField' => 'DifferentialCustomField', 'DifferentialConflictsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialController' => 'PhabricatorController', 'DifferentialCoreCustomField' => 'DifferentialCustomField', @@ -2971,6 +2978,7 @@ phutil_register_library_map(array( 'DifferentialFieldSpecificationIncompleteException' => 'Exception', 'DifferentialFieldValidationException' => 'Exception', 'DifferentialFreeformFieldSpecification' => 'DifferentialFieldSpecification', + 'DifferentialGitSVNIDField' => 'DifferentialCustomField', 'DifferentialGitSVNIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialHostField' => 'DifferentialCustomField', 'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification', @@ -3017,6 +3025,7 @@ phutil_register_library_map(array( 'DifferentialRevertPlanField' => 'DifferentialStoredCustomField', 'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewRequestMail' => 'DifferentialMail', + 'DifferentialReviewedByField' => 'DifferentialCoreCustomField', 'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialReviewersField' => 'DifferentialCoreCustomField', 'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification', @@ -3035,6 +3044,7 @@ phutil_register_library_map(array( 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionEditor' => 'PhabricatorEditor', + 'DifferentialRevisionIDField' => 'DifferentialCustomField', 'DifferentialRevisionIDFieldParserTestCase' => 'PhabricatorTestCase', 'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevisionLandController' => 'DifferentialController', diff --git a/src/applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php b/src/applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php index 0922866fd2..287c620732 100644 --- a/src/applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php +++ b/src/applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php @@ -1,8 +1,5 @@ withIDs(array($id)) ->setViewer($viewer) - ->needRelationships(true) ->needReviewerStatus(true) + ->needActiveDiffs(true) ->executeOne(); - if (!$revision) { throw new ConduitException('ERR_NOT_FOUND'); } } else { $revision = DifferentialRevision::initializeNewRevision($viewer); + $revision->attachReviewerStatus(array()); + $revision->attachActiveDiff(null); } - $is_edit = $request->getValue('edit'); $is_create = ($is_edit == 'create'); - $aux_fields = DifferentialFieldSelector::newSelector() - ->getFieldSpecifications(); - - $pro_tips = array(); - - foreach ($aux_fields as $key => $aux_field) { - $aux_field->setUser($viewer); - $aux_field->setRevision($revision); - $pro_tips[] = $aux_field->getCommitMessageTips(); - if (!$aux_field->shouldAppearOnCommitMessage()) { - unset($aux_fields[$key]); - } - } - - $aux_fields = DifferentialAuxiliaryField::loadFromStorage( + $field_list = PhabricatorCustomField::getObjectFields( $revision, - $aux_fields); - $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey'); + ($is_edit + ? DifferentialCustomField::ROLE_COMMITMESSAGEEDIT + : DifferentialCustomField::ROLE_COMMITMESSAGE)); + + $field_list + ->setViewer($viewer) + ->readFieldsFromStorage($revision); + + $field_map = mpull($field_list->getFields(), null, 'getFieldKeyForConduit'); if ($is_edit) { - $fields = $request->getValue('fields'); - if (!is_array($fields)) { - $fields = array(); - } + $fields = $request->getValue('fields', array()); foreach ($fields as $field => $value) { - - $aux_field = idx($aux_fields, $field); - if (!$aux_field) { + $custom_field = idx($field_map, $field); + if (!$custom_field) { throw new Exception( - "Commit message includes field '{$field}' which does not ". - "correspond to any configured field."); + pht( + 'Commit message includes field "%s", but this field does not '. + 'correspond to a known field.', + $field)); } - if ($is_create || - $aux_field->shouldOverwriteWhenCommitMessageIsEdited()) { - $aux_field->setValueFromParsedCommitMessage($value); + $custom_field->shouldOverwriteWhenCommitMessageIsEdited()) { + $custom_field->readValueFromCommitMessage($value); } } } - - $aux_phids = array(); - foreach ($aux_fields as $field_key => $field) { - $aux_phids[$field_key] = $field->getRequiredHandlePHIDsForCommitMessage(); - } - $phids = array_unique(array_mergev($aux_phids)); - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($request->getUser()) - ->withPHIDs($phids) - ->execute(); - foreach ($aux_fields as $field_key => $field) { - $field->setHandles(array_select_keys($handles, $aux_phids[$field_key])); + $phids = array(); + foreach ($field_list->getFields() as $key => $field) { + $field_phids = $field->getRequiredHandlePHIDsForCommitMessage(); + if (!is_array($field_phids)) { + throw new Exception( + pht( + 'Custom field "%s" was expected to return an array of handle '. + 'PHIDs required for commit message rendering, but returned "%s" '. + 'instead.', + $field->getFieldKey(), + gettype($field_phids))); + } + $phids[$key] = $field_phids; } + $all_phids = array_mergev($phids); + if ($all_phids) { + $all_handles = id(new PhabricatorHandleQuery()) + ->setViewer($viewer) + ->withPHIDs($all_phids) + ->execute(); + } else { + $all_handles = array(); + } + + $key_title = id(new DifferentialTitleField())->getFieldKey(); + $default_title = DifferentialTitleField::getDefaultTitle(); $commit_message = array(); - foreach ($aux_fields as $field_key => $field) { - $value = $field->renderValueForCommitMessage($is_edit); - $label = $field->renderLabelForCommitMessage(); + foreach ($field_list->getFields() as $key => $field) { + $handles = array_select_keys($all_handles, $phids[$key]); + + $label = $field->renderCommitMessageLabel(); + $value = $field->renderCommitMessageValue($handles); + + if (!is_string($value) && !is_null($value)) { + throw new Exception( + pht( + 'Custom field "%s" was expected to render a string or null value, '. + 'but rendered a "%s" instead.', + $field->getFieldKey(), + gettype($value))); + } + + $is_title = ($key == $key_title); + if (!strlen($value)) { - if ($field_key === 'title') { - $commit_message[] = - DifferentialTitleFieldSpecification::getDefaultRevisionTitle(); + if ($is_title) { + $commit_message[] = $default_title; } else { - if ($field->shouldAppearOnCommitMessageTemplate() && $is_edit) { + if ($is_edit && $field->shouldAppearInCommitMessageTemplate()) { $commit_message[] = $label.': '; } } } else { - if ($field_key === 'title') { + if ($is_title) { $commit_message[] = $value; } else { $value = str_replace( @@ -137,21 +150,9 @@ final class ConduitAPI_differential_getcommitmessage_Method } if ($is_edit) { - $pro_tips = array_mergev($pro_tips); - - if (!empty($pro_tips)) { - shuffle($pro_tips); - $pro_tip = "Tip: ".$pro_tips[0]; - $pro_tip = wordwrap($pro_tip, 78, "\n", true); - - $lines = explode("\n", $pro_tip); - - foreach ($lines as $key => $line) { - $lines[$key] = "# ".$line; - } - - $pro_tip = implode("\n", $lines); - $commit_message[] = $pro_tip; + $tip = $this->getProTip($field_list); + if ($tip !== null) { + $commit_message[] = "\n".$tip; } } @@ -160,4 +161,34 @@ final class ConduitAPI_differential_getcommitmessage_Method return $commit_message; } + private function getProTip() { + // Any field can provide tips, whether it normally appears on commit + // messages or not. + $field_list = PhabricatorCustomField::getObjectFields( + new DifferentialRevision(), + PhabricatorCustomField::ROLE_DEFAULT); + + $tips = array(); + foreach ($field_list->getFields() as $key => $field) { + $tips[] = $field->getProTips(); + } + $tips = array_mergev($tips); + + if (!$tips) { + return null; + } + + shuffle($tips); + + $tip = pht('Tip: %s', head($tips)); + $tip = wordwrap($tip, 78, "\n", true); + + $lines = explode("\n", $tip); + foreach ($lines as $key => $line) { + $lines[$key] = "# ".$line; + } + + return implode("\n", $lines); + } + } diff --git a/src/applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php b/src/applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php index 7588966658..ec54f4d55e 100644 --- a/src/applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php +++ b/src/applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php @@ -1,15 +1,12 @@ getUser(); $corpus = $request->getValue('corpus'); $is_partial = $request->getValue('partial'); - $aux_fields = DifferentialFieldSelector::newSelector() - ->getFieldSpecifications(); + $revision = new DifferentialRevision(); - foreach ($aux_fields as $key => $aux_field) { - $aux_field->setUser($request->getUser()); - if (!$aux_field->shouldAppearOnCommitMessage()) { - unset($aux_fields[$key]); - } - } - - $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey'); + $field_list = PhabricatorCustomField::getObjectFields( + $revision, + DifferentialCustomField::ROLE_COMMITMESSAGE); + $field_list->setViewer($viewer); + $field_map = mpull($field_list->getFields(), null, 'getFieldKeyForConduit'); $this->errors = array(); - // Build a map from labels (like "Test Plan") to field keys - // (like "testPlan"). - $label_map = $this->buildLabelMap($aux_fields); - $field_map = $this->parseCommitMessage($corpus, $label_map); + $label_map = $this->buildLabelMap($field_list); + $corpus_map = $this->parseCommitMessage($corpus, $label_map); + + $values = array(); + foreach ($corpus_map as $field_key => $text_value) { + $field = idx($field_map, $field_key); + + if (!$field) { + throw new Exception( + pht( + 'Parser emitted text value for field key "%s", but no such '. + 'field exists.', + $field_key)); + } - $fields = array(); - foreach ($field_map as $field_key => $field_value) { - $field = $aux_fields[$field_key]; try { - $fields[$field_key] = $field->parseValueFromCommitMessage($field_value); - $field->setValueFromParsedCommitMessage($fields[$field_key]); + $values[$field_key] = $field->parseValueFromCommitMessage($text_value); } catch (DifferentialFieldParseException $ex) { - $field_label = $field->renderLabelForCommitMessage(); - $this->errors[] = - "Error parsing field '{$field_label}': ".$ex->getMessage(); + $this->errors[] = pht( + 'Error parsing field "%s": %s', + $field->renderCommitMessageLabel(), + $ex->getMessage()); } } if (!$is_partial) { - foreach ($aux_fields as $field_key => $aux_field) { + foreach ($field_map as $key => $field) { try { - $aux_field->validateField(); + $field->validateCommitMessageValue(idx($values, $key)); } catch (DifferentialFieldValidationException $ex) { - $field_label = $aux_field->renderLabelForCommitMessage(); - $this->errors[] = - "Invalid or missing field '{$field_label}': ". - $ex->getMessage(); + $this->errors[] = pht( + 'Invalid or missing field "%s": %s', + $field->renderCommitMessageLabel(), + $ex->getMessage()); } } } return array( 'errors' => $this->errors, - 'fields' => $fields, + 'fields' => $values, ); } - private function buildLabelMap(array $aux_fields) { - assert_instances_of($aux_fields, 'DifferentialFieldSpecification'); + private function buildLabelMap(PhabricatorCustomFieldList $field_list) { $label_map = array(); - foreach ($aux_fields as $key => $aux_field) { - $labels = $aux_field->getSupportedCommitMessageLabels(); + + foreach ($field_list->getFields() as $key => $field) { + $labels = $field->getCommitMessageLabels(); + $key = $field->getFieldKeyForConduit(); + foreach ($labels as $label) { $normal_label = DifferentialCommitMessageParser::normalizeFieldLabel( $label); if (!empty($label_map[$normal_label])) { - $previous = $label_map[$normal_label]; throw new Exception( - "Field label '{$label}' is parsed by two fields: '{$key}' and ". - "'{$previous}'. Each label must be parsed by only one field."); + pht( + 'Field label "%s" is parsed by two custom fields: "%s" and '. + '"%s". Each label must be parsed by only one field.', + $label, + $key, + $label_map[$normal_label])); } $label_map[$normal_label] = $key; } } + return $label_map; } private function parseCommitMessage($corpus, array $label_map) { + $key_title = id(new DifferentialTitleField())->getFieldKeyForConduit(); + $key_summary = id(new DifferentialSummaryField())->getFieldKeyForConduit(); + $parser = id(new DifferentialCommitMessageParser()) ->setLabelMap($label_map) - ->setTitleKey('title') - ->setSummaryKey('summary'); + ->setTitleKey($key_title) + ->setSummaryKey($key_summary); $result = $parser->parseCorpus($corpus); diff --git a/src/applications/differential/customfield/DifferentialAuditorsField.php b/src/applications/differential/customfield/DifferentialAuditorsField.php new file mode 100644 index 0000000000..6bb32523ed --- /dev/null +++ b/src/applications/differential/customfield/DifferentialAuditorsField.php @@ -0,0 +1,53 @@ +getValue()); + } + + public function setValueFromStorage($value) { + $this->setValue(phutil_json_decode($value)); + return $this; + } + + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAllowEditInCommitMessage() { + return true; + } + + public function getRequiredHandlePHIDsForCommitMessage() { + return nonempty($this->getValue(), array()); + } + + public function parseCommitMessageValue($value) { + return $this->parseObjectList( + $value, + array( + PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorProjectPHIDTypeProject::TYPECONST, + )); + } + + public function renderCommitMessageValue(array $handles) { + return $this->renderObjectList($handles); + } + + +} diff --git a/src/applications/differential/customfield/DifferentialBlameRevisionField.php b/src/applications/differential/customfield/DifferentialBlameRevisionField.php index fd8fed7190..3c894c0282 100644 --- a/src/applications/differential/customfield/DifferentialBlameRevisionField.php +++ b/src/applications/differential/customfield/DifferentialBlameRevisionField.php @@ -7,6 +7,10 @@ final class DifferentialBlameRevisionField return 'phabricator:blame-revision'; } + public function getFieldKeyForConduit() { + return 'blameRevision'; + } + public function getFieldName() { return pht('Blame Revision'); } @@ -84,4 +88,27 @@ final class DifferentialBlameRevisionField $xaction->renderHandleLink($object_phid)); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAllowEditInCommitMessage() { + return true; + } + + public function shouldOverwriteWhenCommitMessageIsEdited() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'Blame Revision', + 'Blame Rev', + ); + } + + public function renderCommitMessageValue() { + return $this->getValue(); + } + } diff --git a/src/applications/differential/customfield/DifferentialConflictsField.php b/src/applications/differential/customfield/DifferentialConflictsField.php new file mode 100644 index 0000000000..ac5c75326f --- /dev/null +++ b/src/applications/differential/customfield/DifferentialConflictsField.php @@ -0,0 +1,45 @@ +value; } + public function readValueFromCommitMessage($value) { + $this->setValue($value); + return $this; + } + + public function renderCommitMessageValue(array $handles) { + return $this->getValue(); + } + } diff --git a/src/applications/differential/customfield/DifferentialCustomField.php b/src/applications/differential/customfield/DifferentialCustomField.php index 88b4f24e77..3ad9e56a0c 100644 --- a/src/applications/differential/customfield/DifferentialCustomField.php +++ b/src/applications/differential/customfield/DifferentialCustomField.php @@ -1,10 +1,34 @@ getFieldKey(); + } + + public function shouldEnableForRole($role) { + switch ($role) { + case self::ROLE_COMMITMESSAGE: + return $this->shouldAppearInCommitMessage(); + case self::ROLE_COMMITMESSAGEEDIT: + return $this->shouldAppearInCommitMessage() && + $this->shouldAllowEditInCommitMessage(); + } + + return parent::shouldEnableForRole($role); } protected function renderHandleList(array $handles) { @@ -20,4 +44,172 @@ abstract class DifferentialCustomField return phutil_implode_html(phutil_tag('br'), $out); } + public function getRequiredDiffPropertiesForRevisionView() { + if ($this->getProxy()) { + return $this->getProxy()->getRequiredDiffPropertiesForRevisionView(); + } + return array(); + } + + protected function parseObjectList($value, array $types) { + return id(new PhabricatorObjectListQuery()) + ->setViewer($this->getViewer()) + ->setAllowedTypes($types) + ->setObjectList($value) + ->execute(); + } + + protected function renderObjectList(array $handles) { + if (!$handles) { + return null; + } + + $out = array(); + foreach ($handles as $handle) { + if ($handle->getPolicyFiltered()) { + $out[] = $handle->getPHID(); + } else if ($handle->isComplete()) { + $out[] = $handle->getObjectName(); + } + } + + return implode(', ', $out); + } + + +/* -( Integration with Commit Messages )----------------------------------- */ + + + /** + * @task commitmessage + */ + public function shouldAppearInCommitMessage() { + if ($this->getProxy()) { + return $this->getProxy()->shouldAppearInCommitMessage(); + } + return false; + } + + + /** + * @task commitmessage + */ + public function shouldAppearInCommitMessageTemplate() { + if ($this->getProxy()) { + return $this->getProxy()->shouldAppearInCommitMessageTemplate(); + } + return false; + } + + + /** + * @task commitmessage + */ + public function shouldAllowEditInCommitMessage() { + if ($this->getProxy()) { + return $this->getProxy()->shouldAllowEditInCommitMessage(); + } + return true; + } + + + /** + * @task commitmessage + */ + public function getProTips() { + if ($this->getProxy()) { + return $this->getProxy()->getProTips(); + } + return array(); + } + + + /** + * @task commitmessage + */ + public function getCommitMessageLabels() { + if ($this->getProxy()) { + return $this->getProxy()->getCommitMessageLabels(); + } + return array($this->renderCommitMessageLabel()); + } + + + /** + * @task commitmessage + */ + public function parseValueFromCommitMessage($value) { + if ($this->getProxy()) { + return $this->getProxy()->parseValueFromCommitMessage($value); + } + return $value; + } + + + /** + * @task commitmessage + */ + public function readValueFromCommitMessage($value) { + if ($this->getProxy()) { + $this->getProxy()->readValueFromCommitMessage($value); + return $this; + } + return $this; + } + + + /** + * @task commitmessage + */ + public function shouldOverwriteWhenCommitMessageIsEdited() { + if ($this->getProxy()) { + return $this->getProxy()->shouldOverwriteWhenCommitMessageIsEdited(); + } + return false; + } + + + /** + * @task commitmessage + */ + public function getRequiredHandlePHIDsForCommitMessage() { + if ($this->getProxy()) { + return $this->getProxy()->getRequiredHandlePHIDsForCommitMessage(); + } + return array(); + } + + + /** + * @task commitmessage + */ + public function renderCommitMessageLabel() { + if ($this->getProxy()) { + return $this->getProxy()->renderCommitMessageLabel(); + } + return $this->getFieldName(); + } + + + /** + * @task commitmessage + */ + public function renderCommitMessageValue(array $handles) { + if ($this->getProxy()) { + return $this->getProxy()->renderCommitMessageValue($handles); + } + throw new PhabricatorCustomFieldImplementationIncompleteException($this); + } + + + /** + * @task commitmessage + */ + public function validateCommitMessageValue($value) { + if ($this->getProxy()) { + return $this->getProxy()->validateCommitMessageValue($value); + } + return; + } + } diff --git a/src/applications/differential/customfield/DifferentialDependsOnField.php b/src/applications/differential/customfield/DifferentialDependsOnField.php index a48095a58a..a6b2c998b5 100644 --- a/src/applications/differential/customfield/DifferentialDependsOnField.php +++ b/src/applications/differential/customfield/DifferentialDependsOnField.php @@ -33,4 +33,12 @@ final class DifferentialDependsOnField return $this->renderHandleList($handles); } + public function getProTips() { + return array( + pht( + 'Create a dependendency between revisions by writing '. + '"Depends on D123" in your summary.'), + ); + } + } diff --git a/src/applications/differential/customfield/DifferentialGitSVNIDField.php b/src/applications/differential/customfield/DifferentialGitSVNIDField.php new file mode 100644 index 0000000000..a671e10bd6 --- /dev/null +++ b/src/applications/differential/customfield/DifferentialGitSVNIDField.php @@ -0,0 +1,45 @@ +getValue()); } @@ -232,4 +236,32 @@ final class DifferentialJIRAIssuesField $editor->save(); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAppearInCommitMessageTemplate() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'JIRA', + 'JIRA Issues', + 'JIRA Issue', + ); + } + + public function parseValueFromCommitMessage($value) { + return preg_split('/[\s,]+/', $value, $limit = -1, PREG_SPLIT_NO_EMPTY); + } + + public function renderCommitMessageValue(array $handles) { + $value = $this->getValue(); + if (!$value) { + return null; + } + return implode(', ', $value); + } + } diff --git a/src/applications/differential/customfield/DifferentialManiphestTasksField.php b/src/applications/differential/customfield/DifferentialManiphestTasksField.php index e2d54b307a..2c2b3e9e60 100644 --- a/src/applications/differential/customfield/DifferentialManiphestTasksField.php +++ b/src/applications/differential/customfield/DifferentialManiphestTasksField.php @@ -7,6 +7,10 @@ final class DifferentialManiphestTasksField return 'differential:maniphest-tasks'; } + public function getFieldKeyForConduit() { + return 'maniphestTaskPHIDs'; + } + public function getFieldName() { return pht('Maniphest Tasks'); } @@ -24,6 +28,10 @@ final class DifferentialManiphestTasksField } public function getRequiredHandlePHIDsForPropertyView() { + if (!$this->getObject()->getPHID()) { + return array(); + } + return PhabricatorEdgeQuery::loadDestinationPHIDs( $this->getObject()->getPHID(), PhabricatorEdgeConfig::TYPE_DREV_HAS_RELATED_TASK); @@ -33,4 +41,43 @@ final class DifferentialManiphestTasksField return $this->renderHandleList($handles); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAllowEditInCommitMessage() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'Maniphest Task', + 'Maniphest Tasks', + ); + } + + public function parseValueFromCommitMessage($value) { + return $this->parseObjectList( + $value, + array( + ManiphestPHIDTypeTask::TYPECONST, + )); + } + + public function getRequiredHandlePHIDsForCommitMessage() { + return $this->getRequiredHandlePHIDsForPropertyView(); + } + + public function renderCommitMessageValue(array $handles) { + return $this->renderObjectList($handles); + } + + public function getProTips() { + return array( + pht( + 'Write "Fixes T123" in your summary to automatically close the '. + 'corresponding task when this change lands.'), + ); + } + } diff --git a/src/applications/differential/customfield/DifferentialProjectReviewersField.php b/src/applications/differential/customfield/DifferentialProjectReviewersField.php index d3f6b70705..deacef4dab 100644 --- a/src/applications/differential/customfield/DifferentialProjectReviewersField.php +++ b/src/applications/differential/customfield/DifferentialProjectReviewersField.php @@ -52,4 +52,13 @@ final class DifferentialProjectReviewersField } return $reviewers; } + + public function getProTips() { + return array( + pht( + 'You can add a project as a subscriber or reviewer by writing '. + '"#projectname" in the appropriate field.'), + ); + } + } diff --git a/src/applications/differential/customfield/DifferentialRevertPlanField.php b/src/applications/differential/customfield/DifferentialRevertPlanField.php index e39c373a9d..e8c4055772 100644 --- a/src/applications/differential/customfield/DifferentialRevertPlanField.php +++ b/src/applications/differential/customfield/DifferentialRevertPlanField.php @@ -7,6 +7,10 @@ final class DifferentialRevertPlanField return 'phabricator:revert-plan'; } + public function getFieldKeyForConduit() { + return 'revertPlan'; + } + public function getFieldName() { return pht('Revert Plan'); } @@ -131,4 +135,12 @@ final class DifferentialRevertPlanField return array($xaction->getNewValue()); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function renderCommitMessageValue(array $handles) { + return $this->getValue(); + } + } diff --git a/src/applications/differential/customfield/DifferentialReviewedByField.php b/src/applications/differential/customfield/DifferentialReviewedByField.php new file mode 100644 index 0000000000..a798e0969e --- /dev/null +++ b/src/applications/differential/customfield/DifferentialReviewedByField.php @@ -0,0 +1,58 @@ +getReviewerStatus() as $reviewer) { + switch ($reviewer->getStatus()) { + case DifferentialReviewerStatus::STATUS_ACCEPTED: + case DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER: + $phids[] = $reviewer->getReviewerPHID(); + break; + } + } + + return $phids; + } + + public function shouldAppearInCommitMessage() { + return true; + } + + public function getRequiredHandlePHIDsForCommitMessage() { + return $this->getValue(); + } + + public function renderCommitMessageValue(array $handles) { + return $this->renderObjectList($handles); + } + +} diff --git a/src/applications/differential/customfield/DifferentialReviewersField.php b/src/applications/differential/customfield/DifferentialReviewersField.php index 9f89feec8c..76d13ae18a 100644 --- a/src/applications/differential/customfield/DifferentialReviewersField.php +++ b/src/applications/differential/customfield/DifferentialReviewersField.php @@ -7,6 +7,10 @@ final class DifferentialReviewersField return 'differential:reviewers'; } + public function getFieldKeyForConduit() { + return 'reviewerPHIDs'; + } + public function getFieldName() { return pht('Reviewers'); } @@ -118,4 +122,47 @@ final class DifferentialReviewersField } return $reviewers; } + + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAppearInCommitMessageTemplate() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'Reviewer', + 'Reviewers', + ); + } + + public function parseValueFromCommitMessage($value) { + return $this->parseObjectList( + $value, + array( + PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorProjectPHIDTypeProject::TYPECONST, + )); + } + + public function getRequiredHandlePHIDsForCommitMessage() { + return mpull($this->getValue(), 'getReviewerPHID'); + } + + public function readValueFromCommitMessage($value) { + $reviewers = array(); + foreach ($value as $phid) { + $reviewers[] = new DifferentialReviewer($phid, array()); + } + $this->setValue($reviewers); + + return $this; + } + + public function renderCommitMessageValue(array $handles) { + return $this->renderObjectList($handles); + } + } diff --git a/src/applications/differential/customfield/DifferentialRevisionIDField.php b/src/applications/differential/customfield/DifferentialRevisionIDField.php new file mode 100644 index 0000000000..f4e8110b98 --- /dev/null +++ b/src/applications/differential/customfield/DifferentialRevisionIDField.php @@ -0,0 +1,41 @@ +getObject()->getID()); + } + +} diff --git a/src/applications/differential/customfield/DifferentialSubscribersField.php b/src/applications/differential/customfield/DifferentialSubscribersField.php index 321b7a1838..4d2a9f016a 100644 --- a/src/applications/differential/customfield/DifferentialSubscribersField.php +++ b/src/applications/differential/customfield/DifferentialSubscribersField.php @@ -7,6 +7,10 @@ final class DifferentialSubscribersField return 'differential:subscribers'; } + public function getFieldKeyForConduit() { + return 'ccPHIDs'; + } + public function getFieldName() { return pht('Subscribers'); } @@ -17,6 +21,10 @@ final class DifferentialSubscribersField protected function readValueFromRevision( DifferentialRevision $revision) { + if (!$revision->getPHID()) { + return array(); + } + return PhabricatorSubscribersQuery::loadSubscribersForPHID( $revision->getPHID()); } @@ -46,4 +54,43 @@ final class DifferentialSubscribersField return PhabricatorTransactions::TYPE_SUBSCRIBERS; } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAllowEditInCommitMessage() { + return true; + } + + public function shouldAppearInCommitMessageTemplate() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'CC', + 'CCs', + 'Subscriber', + 'Subscribers', + ); + } + + public function parseValueFromCommitMessage($value) { + return $this->parseObjectList( + $value, + array( + PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorMailingListPHIDTypeList::TYPECONST, + )); + } + + public function getRequiredHandlePHIDsForCommitMessage() { + return $this->getValue(); + } + + public function renderCommitMessageValue(array $handles) { + return $this->renderObjectList($handles); + } + } diff --git a/src/applications/differential/customfield/DifferentialSummaryField.php b/src/applications/differential/customfield/DifferentialSummaryField.php index aa5437b55c..01d43cb5a3 100644 --- a/src/applications/differential/customfield/DifferentialSummaryField.php +++ b/src/applications/differential/customfield/DifferentialSummaryField.php @@ -7,6 +7,10 @@ final class DifferentialSummaryField return 'differential:summary'; } + public function getFieldKeyForConduit() { + return 'summary'; + } + public function getFieldName() { return pht('Summary'); } @@ -123,4 +127,16 @@ final class DifferentialSummaryField return array($xaction->getNewValue()); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAppearInCommitMessageTemplate() { + return true; + } + + public function shouldOverwriteWhenCommitMessageIsEdited() { + return true; + } + } diff --git a/src/applications/differential/customfield/DifferentialTestPlanField.php b/src/applications/differential/customfield/DifferentialTestPlanField.php index ad36b001c8..5b6ffe7ed1 100644 --- a/src/applications/differential/customfield/DifferentialTestPlanField.php +++ b/src/applications/differential/customfield/DifferentialTestPlanField.php @@ -7,6 +7,10 @@ final class DifferentialTestPlanField return 'differential:test-plan'; } + public function getFieldKeyForConduit() { + return 'testPlan'; + } + public function getFieldName() { return pht('Test Plan'); } @@ -36,7 +40,7 @@ final class DifferentialTestPlanField protected function getCoreFieldRequiredErrorString() { return pht( - 'You must provide a test plan: describe the actions you performed '. + 'You must provide a test plan. Describe the actions you performed '. 'to verify the behvaior of this change.'); } @@ -138,4 +142,33 @@ final class DifferentialTestPlanField return array($xaction->getNewValue()); } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldAppearInCommitMessageTemplate() { + return true; + } + + public function shouldOverwriteWhenCommitMessageIsEdited() { + return true; + } + + public function getCommitMessageLabels() { + return array( + 'Test Plan', + 'Testplan', + 'Tested', + 'Tests', + ); + } + + public function validateCommitMessageValue($value) { + if (!strlen($value) && $this->isCoreFieldRequired()) { + throw new DifferentialFieldValidationException( + $this->getCoreFieldRequiredErrorString()); + } + } + + } diff --git a/src/applications/differential/customfield/DifferentialTitleField.php b/src/applications/differential/customfield/DifferentialTitleField.php index 0eb80df825..77cddae751 100644 --- a/src/applications/differential/customfield/DifferentialTitleField.php +++ b/src/applications/differential/customfield/DifferentialTitleField.php @@ -7,6 +7,10 @@ final class DifferentialTitleField return 'differential:title'; } + public function getFieldKeyForConduit() { + return 'title'; + } + public function getFieldName() { return pht('Title'); } @@ -15,6 +19,10 @@ final class DifferentialTitleField return pht('Stores the revision title.'); } + public static function getDefaultTitle() { + return pht('<>'); + } + protected function readValueFromRevision( DifferentialRevision $revision) { return $revision->getTitle(); @@ -90,4 +98,29 @@ final class DifferentialTitleField } } + public function shouldAppearInCommitMessage() { + return true; + } + + public function shouldOverwriteWhenCommitMessageIsEdited() { + return true; + } + + public function validateCommitMessageValue($value) { + if (!strlen($value)) { + throw new DifferentialFieldValidationException( + pht( + "You must provide a revision title in the first line ". + "of your commit message.")); + } + + if (preg_match('/^<<.*>>$/', $value)) { + throw new DifferentialFieldValidationException( + pht( + 'Replace the line "%s" with a human-readable revision title which '. + 'describes the changes you are making.', + self::getDefaultTitle())); + } + } + }