public function copyFieldsFromConduit(array $fields)
 {
     $revision = $this->revision;
     $revision->loadRelationships();
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $this->actorPHID);
     foreach ($aux_fields as $key => $aux_field) {
         $aux_field->setRevision($revision);
         $aux_field->setUser($user);
         if (!$aux_field->shouldAppearOnCommitMessage()) {
             unset($aux_fields[$key]);
         }
     }
     $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
     foreach ($fields as $field => $value) {
         if (empty($aux_fields[$field])) {
             throw new Exception("Parsed commit message contains unrecognized field '{$field}'.");
         }
         $aux_fields[$field]->setValueFromParsedCommitMessage($value);
     }
     foreach ($aux_fields as $aux_field) {
         $aux_field->validateField();
     }
     $aux_fields = array_values($aux_fields);
     $this->setAuxiliaryFields($aux_fields);
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $corpus = $request->getValue('corpus');
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         if (!$aux_field->shouldAppearOnCommitMessage()) {
             unset($aux_fields[$key]);
         }
     }
     $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
     // 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);
     $fields = array();
     $errors = array();
     foreach ($field_map as $field_key => $field_value) {
         $field = $aux_fields[$field_key];
         try {
             $fields[$field_key] = $field->parseValueFromCommitMessage($field_value);
         } catch (DifferentialFieldParseException $ex) {
             $field_label = $field->renderLabelForCommitMessage();
             $errors[] = "Error parsing field '{$field_label}': " . $ex->getMessage();
         }
     }
     // TODO: This is for backcompat only, remove once Arcanist gets updated.
     $error = head($errors);
     return array('error' => $error, 'errors' => $errors, 'fields' => $fields);
 }
 private function loadAuxiliaryFields(DifferentialRevision $revision)
 {
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         if (!$aux_field->shouldAppearOnConduitView()) {
             unset($aux_fields[$key]);
         }
     }
     $aux_fields = DifferentialAuxiliaryField::loadFromStorage($revision, $aux_fields);
     return mpull($aux_fields, 'getValueForConduit', 'getKeyForConduit');
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $corpus = $request->getValue('corpus');
     $is_partial = $request->getValue('partial');
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         if (!$aux_field->shouldAppearOnCommitMessage()) {
             unset($aux_fields[$key]);
         }
         $aux_field->setUser($request->getUser());
     }
     $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
     $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);
     $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]);
         } catch (DifferentialFieldParseException $ex) {
             $field_label = $field->renderLabelForCommitMessage();
             $this->errors[] = "Error parsing field '{$field_label}': " . $ex->getMessage();
         }
     }
     if (!$is_partial) {
         foreach ($aux_fields as $field_key => $aux_field) {
             try {
                 $aux_field->validateField();
             } catch (DifferentialFieldValidationException $ex) {
                 $field_label = $aux_field->renderLabelForCommitMessage();
                 $this->errors[] = "Invalid or missing field '{$field_label}': " . $ex->getMessage();
             }
         }
     }
     return array('errors' => $this->errors, 'fields' => $fields);
 }
 private function loadAuxiliaryFields(DifferentialRevision $revision)
 {
     $user = $this->getRequest()->getUser();
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         $aux_field->setRevision($revision);
         if (!$aux_field->shouldAppearOnEdit()) {
             unset($aux_fields[$key]);
         } else {
             $aux_field->setUser($user);
         }
     }
     return DifferentialAuxiliaryField::loadFromStorage($revision, $aux_fields);
 }
 public static function getDefaultFields()
 {
     $selector = DifferentialFieldSelector::newSelector();
     $fields = $selector->getFieldSpecifications();
     foreach ($fields as $key => $field) {
         if (!$field->shouldAppearOnRevisionList()) {
             unset($fields[$key]);
         }
     }
     if (!$fields) {
         throw new Exception("Phabricator configuration has no fields that appear on the list " . "interface!");
     }
     return $selector->sortFieldsForRevisionList($fields);
 }
 private function loadAuxiliaryFieldsAndProperties(DifferentialRevision $revision, DifferentialDiff $diff, array $special_properties)
 {
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         if (!$aux_field->shouldAppearOnRevisionView()) {
             unset($aux_fields[$key]);
         } else {
             $aux_field->setUser($this->getRequest()->getUser());
         }
     }
     $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);
     $required_properties = array_merge($required_properties, $special_properties);
     $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 array($aux_fields, array_select_keys($property_map, $special_properties));
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $id = $request->getValue('revision_id');
     $revision = id(new DifferentialRevision())->load($id);
     if (!$revision) {
         throw new ConduitException('ERR_NOT_FOUND');
     }
     $revision->loadRelationships();
     $is_edit = $request->getValue('edit');
     $aux_fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
     foreach ($aux_fields as $key => $aux_field) {
         $aux_field->setRevision($revision);
         if (!$aux_field->shouldAppearOnCommitMessage()) {
             unset($aux_fields[$key]);
         }
     }
     $aux_fields = DifferentialAuxiliaryField::loadFromStorage($revision, $aux_fields);
     $aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
     if ($is_edit) {
         $fields = $request->getValue('fields');
         foreach ($fields as $field => $value) {
             $aux_field = idx($aux_fields, $field);
             if (!$aux_field) {
                 throw new Exception("Commit message includes field '{$field}' which does not " . "correspond to any configured field.");
             }
             if ($aux_field->shouldOverwriteWhenCommitMessageIsEdited()) {
                 $aux_field->setValueFromParsedCommitMessage($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 PhabricatorObjectHandleData($phids))->loadHandles();
     foreach ($aux_fields as $field_key => $field) {
         $field->setHandles(array_select_keys($handles, $aux_phids[$field_key]));
     }
     $commit_message = array();
     foreach ($aux_fields as $field_key => $field) {
         $value = $field->renderValueForCommitMessage($is_edit);
         $label = $field->renderLabelForCommitMessage();
         if ($value === null || !strlen($value)) {
             if ($field_key === 'title') {
                 $commit_message[] = '<<Enter Revision Title>>';
             } else {
                 if ($field->shouldAppearOnCommitMessageTemplate() && $is_edit) {
                     $commit_message[] = $label . ': ';
                 }
             }
         } else {
             if ($field_key === 'title') {
                 $commit_message[] = $value;
             } else {
                 $value = str_replace(array("\r\n", "\r"), array("\n", "\n"), $value);
                 if (strpos($value, "\n") !== false) {
                     $commit_message[] = "{$label}:\n{$value}";
                 } else {
                     $commit_message[] = "{$label}: {$value}";
                 }
             }
         }
     }
     $commit_message = implode("\n\n", $commit_message);
     return wordwrap($commit_message, 80);
 }
 protected final function updateCommitData($author, $message, $committer = null)
 {
     $commit = $this->commit;
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     if (!$data) {
         $data = new PhabricatorRepositoryCommitData();
     }
     $data->setCommitID($commit->getID());
     $data->setAuthorName($author);
     $data->setCommitMessage($message);
     if ($committer) {
         $data->setCommitDetail('committer', $committer);
     }
     $repository = $this->repository;
     $detail_parser = $repository->getDetail('detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser');
     if ($detail_parser) {
         $parser_obj = newv($detail_parser, array($commit, $data));
         $parser_obj->parseCommitDetails();
     }
     $author_phid = $this->lookupUser($commit, $data->getAuthorName(), $data->getCommitDetail('authorPHID'));
     $data->setCommitDetail('authorPHID', $author_phid);
     $committer_phid = $this->lookupUser($commit, $data->getCommitDetail('committer'), $data->getCommitDetail('committerPHID'));
     $data->setCommitDetail('committerPHID', $committer_phid);
     if ($author_phid != $commit->getAuthorPHID()) {
         $commit->setAuthorPHID($author_phid);
         $commit->save();
     }
     $conn_w = id(new DifferentialRevision())->establishConnection('w');
     // NOTE: The `differential_commit` table has a unique ID on `commitPHID`,
     // preventing more than one revision from being associated with a commit.
     // Generally this is good and desirable, but with the advent of hash
     // tracking we may end up in a situation where we match several different
     // revisions. We just kind of ignore this and pick one, we might want to
     // revisit this and do something differently. (If we match several revisions
     // someone probably did something very silly, though.)
     $revision = null;
     $should_autoclose = $repository->shouldAutocloseCommit($commit, $data);
     $revision_id = $data->getCommitDetail('differential.revisionID');
     if (!$revision_id) {
         $hashes = $this->getCommitHashes($this->repository, $this->commit);
         if ($hashes) {
             $query = new DifferentialRevisionQuery();
             $query->withCommitHashes($hashes);
             $revisions = $query->execute();
             if (!empty($revisions)) {
                 $revision = $this->identifyBestRevision($revisions);
                 $revision_id = $revision->getID();
             }
         }
     }
     if ($revision_id) {
         $lock = PhabricatorGlobalLock::newLock(get_class($this) . ':' . $revision_id);
         $lock->lock(5 * 60);
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             $revision->loadRelationships();
             queryfx($conn_w, 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID());
             $status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
             $should_close = $revision->getStatus() != $status_closed && $should_autoclose;
             if ($should_close) {
                 $actor_phid = nonempty($committer_phid, $author_phid, $revision->getAuthorPHID());
                 $diff = $this->attachToRevision($revision, $actor_phid);
                 $revision->setDateCommitted($commit->getEpoch());
                 $editor = new DifferentialCommentEditor($revision, $actor_phid, DifferentialAction::ACTION_CLOSE);
                 $editor->setIsDaemonWorkflow(true);
                 $vs_diff = $this->loadChangedByCommit($diff);
                 if ($vs_diff) {
                     $data->setCommitDetail('vsDiff', $vs_diff->getID());
                     $changed_by_commit = PhabricatorEnv::getProductionURI('/D' . $revision->getID() . '?vs=' . $vs_diff->getID() . '&id=' . $diff->getID() . '#toc');
                     $editor->setChangedByCommit($changed_by_commit);
                 }
                 $commit_name = $repository->formatCommitName($commit->getCommitIdentifier());
                 $committer_name = $this->loadUserName($committer_phid, $data->getCommitDetail('committer'));
                 $author_name = $this->loadUserName($author_phid, $data->getAuthorName());
                 $info = array();
                 $info[] = "authored by {$author_name}";
                 if ($committer_name && $committer_name != $author_name) {
                     $info[] = "committed by {$committer_name}";
                 }
                 $info = implode(', ', $info);
                 $editor->setMessage("Closed by commit {$commit_name} ({$info}).")->save();
             }
         }
         $lock->unlock();
     }
     if ($should_autoclose && $author_phid) {
         $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $author_phid);
         $call = new ConduitCall('differential.parsecommitmessage', array('corpus' => $message, 'partial' => true));
         $call->setUser($user);
         $result = $call->execute();
         $field_values = $result['fields'];
         $fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
         foreach ($fields as $key => $field) {
             if (!$field->shouldAppearOnCommitMessage()) {
                 continue;
             }
             $field->setUser($user);
             $value = idx($field_values, $field->getCommitMessageKey());
             $field->setValueFromParsedCommitMessage($value);
             if ($revision) {
                 $field->setRevision($revision);
             }
             $field->didParseCommit($repository, $commit, $data);
         }
     }
     $data->save();
 }
Example #10
0
 protected function renderAuxFields($phase)
 {
     $selector = DifferentialFieldSelector::newSelector();
     $aux_fields = $selector->sortFieldsForMail($selector->getFieldSpecifications());
     $body = array();
     foreach ($aux_fields as $field) {
         $field->setRevision($this->getRevision());
         // TODO: Introduce and use getRequiredHandlePHIDsForMail() and load all
         // handles in prepareBody().
         $text = $field->renderValueForMail($phase);
         if ($text !== null) {
             $body[] = $text;
             $body[] = null;
         }
     }
     return implode("\n", $body);
 }