diff --git a/src/applications/differential/customfield/DifferentialAuditorsField.php b/src/applications/differential/customfield/DifferentialAuditorsField.php index d84fe0eda..3929cf07e 100644 --- a/src/applications/differential/customfield/DifferentialAuditorsField.php +++ b/src/applications/differential/customfield/DifferentialAuditorsField.php @@ -1,60 +1,68 @@ getValue()); } public function setValueFromStorage($value) { try { $this->setValue(phutil_json_decode($value)); } catch (PhutilJSONParserException $ex) { $this->setValue(array()); } return $this; } public function shouldAppearInCommitMessage() { return true; } public function shouldAllowEditInCommitMessage() { return true; } public function canDisableField() { return false; } public function getRequiredHandlePHIDsForCommitMessage() { return nonempty($this->getValue(), array()); } public function parseCommitMessageValue($value) { return $this->parseObjectList( $value, array( PhabricatorPeopleUserPHIDType::TYPECONST, PhabricatorProjectProjectPHIDType::TYPECONST, )); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } + public function shouldAppearInConduitTransactions() { + return true; + } + + protected function newConduitEditParameterType() { + return new ConduitPHIDListParameterType(); + } + } diff --git a/src/applications/differential/customfield/DifferentialBlameRevisionField.php b/src/applications/differential/customfield/DifferentialBlameRevisionField.php index ba2220ae3..99915440c 100644 --- a/src/applications/differential/customfield/DifferentialBlameRevisionField.php +++ b/src/applications/differential/customfield/DifferentialBlameRevisionField.php @@ -1,117 +1,125 @@ getFieldName(); } public function renderPropertyViewValue(array $handles) { return $this->getValue(); } public function shouldAppearInEditView() { return true; } public function shouldAppearInApplicationTransactions() { return true; } public function getOldValueForApplicationTransactions() { return $this->getValue(); } public function getNewValueForApplicationTransactions() { return $this->getValue(); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStr($this->getFieldKey())); } public function renderEditControl(array $handles) { return id(new AphrontFormTextControl()) ->setName($this->getFieldKey()) ->setValue($this->getValue()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the blame revision for this revision.', $xaction->renderHandleLink($author_phid)); } public function getApplicationTransactionTitleForFeed( PhabricatorApplicationTransaction $xaction) { $object_phid = $xaction->getObjectPHID(); $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the blame revision for %s.', $xaction->renderHandleLink($author_phid), $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(array $handles) { return $this->getValue(); } public function shouldAppearInConduitDictionary() { return true; } + public function shouldAppearInConduitTransactions() { + return true; + } + + protected function newConduitEditParameterType() { + return new ConduitStringParameterType(); + } + } diff --git a/src/applications/differential/customfield/DifferentialCustomField.php b/src/applications/differential/customfield/DifferentialCustomField.php index d0980736c..f210dd0f6 100644 --- a/src/applications/differential/customfield/DifferentialCustomField.php +++ b/src/applications/differential/customfield/DifferentialCustomField.php @@ -1,263 +1,268 @@ getFieldKey(); } + // TODO: As above. + public function getModernFieldKey() { + return $this->getFieldKeyForConduit(); + } + 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 parseObjectList( $value, array $types, $allow_partial = false, array $suffixes = array()) { return id(new PhabricatorObjectListQuery()) ->setViewer($this->getViewer()) ->setAllowedTypes($types) ->setObjectList($value) ->setAllowPartialResults($allow_partial) ->setSuffixes($suffixes) ->execute(); } protected function renderObjectList( array $handles, array $suffixes = array()) { if (!$handles) { return null; } $out = array(); foreach ($handles as $handle) { $phid = $handle->getPHID(); if ($handle->getPolicyFiltered()) { $token = $phid; } else if ($handle->isComplete()) { $token = $handle->getCommandLineObjectName(); } $suffix = idx($suffixes, $phid); $token = $token.$suffix; $out[] = $token; } return implode(', ', $out); } public function getWarningsForDetailView() { if ($this->getProxy()) { return $this->getProxy()->getWarningsForDetailView(); } return array(); } public function getRequiredHandlePHIDsForRevisionHeaderWarnings() { return array(); } public function getWarningsForRevisionHeader(array $handles) { return array(); } /* -( 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; } /* -( Integration with Diff Properties )----------------------------------- */ /** * @task diff */ public function shouldAppearInDiffPropertyView() { if ($this->getProxy()) { return $this->getProxy()->shouldAppearInDiffPropertyView(); } return false; } /** * @task diff */ public function renderDiffPropertyViewLabel(DifferentialDiff $diff) { if ($this->proxy) { return $this->proxy->renderDiffPropertyViewLabel($diff); } return $this->getFieldName(); } /** * @task diff */ public function renderDiffPropertyViewValue(DifferentialDiff $diff) { if ($this->proxy) { return $this->proxy->renderDiffPropertyViewValue($diff); } throw new PhabricatorCustomFieldImplementationIncompleteException($this); } } diff --git a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php index e40e34f4a..fc15f4a45 100644 --- a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php +++ b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php @@ -1,313 +1,318 @@ getValue()); } public function setValueFromStorage($value) { try { $this->setValue(phutil_json_decode($value)); } catch (PhutilJSONParserException $ex) { $this->setValue(array()); } return $this; } public function getFieldName() { return pht('JIRA Issues'); } public function getFieldDescription() { return pht('Lists associated JIRA issues.'); } public function shouldAppearInPropertyView() { return true; } public function renderPropertyViewLabel() { return $this->getFieldName(); } public function renderPropertyViewValue(array $handles) { $xobjs = $this->loadDoorkeeperExternalObjects($this->getValue()); if (!$xobjs) { return null; } $links = array(); foreach ($xobjs as $xobj) { $links[] = id(new DoorkeeperTagView()) ->setExternalObject($xobj); } return phutil_implode_html(phutil_tag('br'), $links); } private function buildDoorkeeperRefs($value) { $provider = PhabricatorJIRAAuthProvider::getJIRAProvider(); $refs = array(); if ($value) { foreach ($value as $jira_key) { $refs[] = id(new DoorkeeperObjectRef()) ->setApplicationType(DoorkeeperBridgeJIRA::APPTYPE_JIRA) ->setApplicationDomain($provider->getProviderDomain()) ->setObjectType(DoorkeeperBridgeJIRA::OBJTYPE_ISSUE) ->setObjectID($jira_key); } } return $refs; } private function loadDoorkeeperExternalObjects($value) { $refs = $this->buildDoorkeeperRefs($value); if (!$refs) { return array(); } $xobjs = id(new DoorkeeperExternalObjectQuery()) ->setViewer($this->getViewer()) ->withObjectKeys(mpull($refs, 'getObjectKey')) ->execute(); return $xobjs; } public function shouldAppearInEditView() { return PhabricatorJIRAAuthProvider::getJIRAProvider(); } public function shouldAppearInApplicationTransactions() { return PhabricatorJIRAAuthProvider::getJIRAProvider(); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStrList($this->getFieldKey())); return $this; } public function renderEditControl(array $handles) { return id(new AphrontFormTextControl()) ->setLabel(pht('JIRA Issues')) ->setCaption( pht('Example: %s', phutil_tag('tt', array(), 'JIS-3, JIS-9'))) ->setName($this->getFieldKey()) ->setValue(implode(', ', nonempty($this->getValue(), array()))) ->setError($this->error); } public function getOldValueForApplicationTransactions() { return array_unique(nonempty($this->getValue(), array())); } public function getNewValueForApplicationTransactions() { return array_unique(nonempty($this->getValue(), array())); } public function validateApplicationTransactions( PhabricatorApplicationTransactionEditor $editor, $type, array $xactions) { $this->error = null; $errors = parent::validateApplicationTransactions( $editor, $type, $xactions); $transaction = null; foreach ($xactions as $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); $add = array_diff($new, $old); if (!$add) { continue; } // Only check that the actor can see newly added JIRA refs. You're // allowed to remove refs or make no-op changes even if you aren't // linked to JIRA. try { $refs = id(new DoorkeeperImportEngine()) ->setViewer($this->getViewer()) ->setRefs($this->buildDoorkeeperRefs($add)) ->setThrowOnMissingLink(true) ->execute(); } catch (DoorkeeperMissingLinkException $ex) { $this->error = pht('Not Linked'); $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Not Linked'), pht( 'You can not add JIRA issues (%s) to this revision because your '. 'Phabricator account is not linked to a JIRA account.', implode(', ', $add)), $xaction); continue; } $bad = array(); foreach ($refs as $ref) { if (!$ref->getIsVisible()) { $bad[] = $ref->getObjectID(); } } if ($bad) { $bad = implode(', ', $bad); $this->error = pht('Invalid'); $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht( 'Some JIRA issues could not be loaded. They may not exist, or '. 'you may not have permission to view them: %s', $bad), $xaction); } } return $errors; } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $old = $xaction->getOldValue(); if (!is_array($old)) { $old = array(); } $new = $xaction->getNewValue(); if (!is_array($new)) { $new = array(); } $add = array_diff($new, $old); $rem = array_diff($old, $new); $author_phid = $xaction->getAuthorPHID(); if ($add && $rem) { return pht( '%s updated JIRA issue(s): added %d %s; removed %d %s.', $xaction->renderHandleLink($author_phid), phutil_count($add), implode(', ', $add), phutil_count($rem), implode(', ', $rem)); } else if ($add) { return pht( '%s added %d JIRA issue(s): %s.', $xaction->renderHandleLink($author_phid), phutil_count($add), implode(', ', $add)); } else if ($rem) { return pht( '%s removed %d JIRA issue(s): %s.', $xaction->renderHandleLink($author_phid), phutil_count($rem), implode(', ', $rem)); } return parent::getApplicationTransactionTitle($xaction); } public function applyApplicationTransactionExternalEffects( PhabricatorApplicationTransaction $xaction) { // Update the CustomField storage. parent::applyApplicationTransactionExternalEffects($xaction); // Now, synchronize the Doorkeeper edges. $revision = $this->getObject(); $revision_phid = $revision->getPHID(); $edge_type = PhabricatorJiraIssueHasObjectEdgeType::EDGECONST; $xobjs = $this->loadDoorkeeperExternalObjects($xaction->getNewValue()); $edge_dsts = mpull($xobjs, 'getPHID'); $edges = PhabricatorEdgeQuery::loadDestinationPHIDs( $revision_phid, $edge_type); $editor = new PhabricatorEdgeEditor(); foreach (array_diff($edges, $edge_dsts) as $rem_edge) { $editor->removeEdge($revision_phid, $edge_type, $rem_edge); } foreach (array_diff($edge_dsts, $edges) as $add_edge) { $editor->addEdge($revision_phid, $edge_type, $add_edge); } $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 readValueFromCommitMessage($value) { $this->setValue($value); return $this; } - - public function renderCommitMessageValue(array $handles) { $value = $this->getValue(); if (!$value) { return null; } return implode(', ', $value); } public function shouldAppearInConduitDictionary() { return true; } + public function shouldAppearInConduitTransactions() { + return true; + } + + protected function newConduitEditParameterType() { + return new ConduitStringListParameterType(); + } } diff --git a/src/applications/differential/customfield/DifferentialRevertPlanField.php b/src/applications/differential/customfield/DifferentialRevertPlanField.php index 646116c74..0fd553142 100644 --- a/src/applications/differential/customfield/DifferentialRevertPlanField.php +++ b/src/applications/differential/customfield/DifferentialRevertPlanField.php @@ -1,145 +1,153 @@ getFieldName(); } public function getStyleForPropertyView() { return 'block'; } public function getIconForPropertyView() { return PHUIPropertyListView::ICON_TESTPLAN; } public function renderPropertyViewValue(array $handles) { if (!strlen($this->getValue())) { return null; } return new PHUIRemarkupView($this->getViewer(), $this->getValue()); } public function shouldAppearInGlobalSearch() { return true; } public function updateAbstractDocument( PhabricatorSearchAbstractDocument $document) { if (strlen($this->getValue())) { $document->addField('rvrt', $this->getValue()); } } public function shouldAppearInEditView() { return true; } public function shouldAppearInApplicationTransactions() { return true; } public function getOldValueForApplicationTransactions() { return $this->getValue(); } public function getNewValueForApplicationTransactions() { return $this->getValue(); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStr($this->getFieldKey())); } public function renderEditControl(array $handles) { return id(new PhabricatorRemarkupControl()) ->setUser($this->getViewer()) ->setName($this->getFieldKey()) ->setValue($this->getValue()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the revert plan for this revision.', $xaction->renderHandleLink($author_phid)); } public function getApplicationTransactionTitleForFeed( PhabricatorApplicationTransaction $xaction) { $object_phid = $xaction->getObjectPHID(); $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the revert plan for %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid)); } public function getApplicationTransactionHasChangeDetails( PhabricatorApplicationTransaction $xaction) { return true; } public function getApplicationTransactionChangeDetails( PhabricatorApplicationTransaction $xaction, PhabricatorUser $viewer) { return $xaction->renderTextCorpusChangeDetails( $viewer, $xaction->getOldValue(), $xaction->getNewValue()); } public function getApplicationTransactionRemarkupBlocks( PhabricatorApplicationTransaction $xaction) { return array($xaction->getNewValue()); } public function shouldAppearInCommitMessage() { return true; } public function renderCommitMessageValue(array $handles) { return $this->getValue(); } public function shouldAppearInConduitDictionary() { return true; } + public function shouldAppearInConduitTransactions() { + return true; + } + + protected function newConduitEditParameterType() { + return new ConduitStringParameterType(); + } + } diff --git a/src/applications/differential/field/DifferentialCommitMessageCustomField.php b/src/applications/differential/field/DifferentialCommitMessageCustomField.php index b53b8d314..cfa71a2a5 100644 --- a/src/applications/differential/field/DifferentialCommitMessageCustomField.php +++ b/src/applications/differential/field/DifferentialCommitMessageCustomField.php @@ -1,68 +1,72 @@ getCustomFieldKey(); return 100000 + $this->getCustomFieldOrder($custom_key); } public function isFieldEnabled() { $custom_key = $this->getCustomFieldKey(); return $this->isCustomFieldEnabled($custom_key); } public function readFieldValueFromObject(DifferentialRevision $revision) { $custom_key = $this->getCustomFieldKey(); $value = $this->readCustomFieldValue($revision, $custom_key); return $value; } protected function readFieldValueFromCustomFieldStorage($value) { return $value; } protected function readJSONFieldValueFromCustomFieldStorage( $value, $default) { try { return phutil_json_decode($value); } catch (PhutilJSONParserException $ex) { return $default; } } protected function readCustomFieldValue( DifferentialRevision $revision, $key) { $value = idx($this->getCustomFieldStorage(), $key); return $this->readFieldValueFromCustomFieldStorage($value); } protected function getCustomFieldOrder($key) { $field_list = PhabricatorCustomField::getObjectFields( new DifferentialRevision(), DifferentialCustomField::ROLE_COMMITMESSAGE); $fields = $field_list->getFields(); $idx = 0; foreach ($fields as $field_key => $value) { if ($key === $field_key) { return $idx; } $idx++; } return $idx; } public function getFieldTransactions($value) { - // TODO: Implement this! - return array(); + return array( + array( + 'type' => $this->getCommitMessageFieldKey(), + 'value' => $value, + ), + ); } } diff --git a/src/applications/transactions/edittype/PhabricatorEditType.php b/src/applications/transactions/edittype/PhabricatorEditType.php index 298238aeb..1451ec2c0 100644 --- a/src/applications/transactions/edittype/PhabricatorEditType.php +++ b/src/applications/transactions/edittype/PhabricatorEditType.php @@ -1,158 +1,165 @@ label = $label; return $this; } public function getLabel() { return $this->label; } public function setField(PhabricatorEditField $field) { $this->field = $field; return $this; } public function getField() { return $this->field; } public function setEditType($edit_type) { $this->editType = $edit_type; return $this; } public function getEditType() { return $this->editType; } public function setMetadata($metadata) { $this->metadata = $metadata; return $this; } public function getMetadata() { return $this->metadata; } public function setTransactionType($transaction_type) { $this->transactionType = $transaction_type; return $this; } public function getTransactionType() { return $this->transactionType; } abstract public function generateTransactions( PhabricatorApplicationTransaction $template, array $spec); protected function newTransaction( PhabricatorApplicationTransaction $template) { $xaction = id(clone $template) ->setTransactionType($this->getTransactionType()); foreach ($this->getMetadata() as $key => $value) { $xaction->setMetadataValue($key, $value); } return $xaction; } public function setEditField(PhabricatorEditField $edit_field) { $this->editField = $edit_field; return $this; } public function getEditField() { return $this->editField; } /* -( Conduit )------------------------------------------------------------ */ protected function newConduitParameterType() { if ($this->conduitParameterType) { return clone $this->conduitParameterType; } return null; } public function setConduitParameterType(ConduitParameterType $type) { $this->conduitParameterType = $type; return $this; } public function getConduitParameterType() { return $this->newConduitParameterType(); } public function getConduitType() { $parameter_type = $this->getConduitParameterType(); + if (!$parameter_type) { + throw new Exception( + pht( + 'Edit type (with key "%s") is missing a Conduit parameter type.', + $this->getEditType())); + } + return $parameter_type->getTypeName(); } public function setConduitTypeDescription($conduit_type_description) { $this->conduitTypeDescription = $conduit_type_description; return $this; } public function getConduitTypeDescription() { if ($this->conduitTypeDescription === null) { if ($this->getEditField()) { return $this->getEditField()->getConduitTypeDescription(); } } return $this->conduitTypeDescription; } public function setConduitDescription($conduit_description) { $this->conduitDescription = $conduit_description; return $this; } public function getConduitDescription() { if ($this->conduitDescription === null) { if ($this->getEditField()) { return $this->getEditField()->getConduitDescription(); } } return $this->conduitDescription; } public function setConduitDocumentation($conduit_documentation) { $this->conduitDocumentation = $conduit_documentation; return $this; } public function getConduitDocumentation() { if ($this->conduitDocumentation === null) { if ($this->getEditField()) { return $this->getEditField()->getConduitDocumentation(); } } return $this->conduitDocumentation; } }