Differential D17058 Diff 41038 src/applications/differential/parser/DifferentialCommitMessageParser.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/differential/parser/DifferentialCommitMessageParser.php
| Show All 20 Lines | |||||
| */ | */ | ||||
| final class DifferentialCommitMessageParser extends Phobject { | final class DifferentialCommitMessageParser extends Phobject { | ||||
| private $viewer; | private $viewer; | ||||
| private $labelMap; | private $labelMap; | ||||
| private $titleKey; | private $titleKey; | ||||
| private $summaryKey; | private $summaryKey; | ||||
| private $errors; | private $errors; | ||||
| private $commitMessageFields; | |||||
| private $raiseMissingFieldErrors = true; | private $raiseMissingFieldErrors = true; | ||||
| public static function newStandardParser(PhabricatorUser $viewer) { | public static function newStandardParser(PhabricatorUser $viewer) { | ||||
| $key_title = DifferentialTitleCommitMessageField::FIELDKEY; | |||||
| $key_summary = DifferentialSummaryCommitMessageField::FIELDKEY; | |||||
| $key_title = id(new DifferentialTitleField())->getFieldKeyForConduit(); | $field_list = DifferentialCommitMessageField::newEnabledFields($viewer); | ||||
| $key_summary = id(new DifferentialSummaryField())->getFieldKeyForConduit(); | |||||
| $field_list = PhabricatorCustomField::getObjectFields( | |||||
| new DifferentialRevision(), | |||||
| DifferentialCustomField::ROLE_COMMITMESSAGE); | |||||
| $field_list->setViewer($viewer); | |||||
| $label_map = array(); | |||||
| foreach ($field_list->getFields() as $field) { | |||||
| $labels = $field->getCommitMessageLabels(); | |||||
| $key = $field->getFieldKeyForConduit(); | |||||
| foreach ($labels as $label) { | |||||
| $normal_label = self::normalizeFieldLabel( | |||||
| $label); | |||||
| if (!empty($label_map[$normal_label])) { | |||||
| throw new Exception( | |||||
| 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 id(new self()) | return id(new self()) | ||||
| ->setViewer($viewer) | ->setViewer($viewer) | ||||
| ->setLabelMap($label_map) | ->setCommitMessageFields($field_list) | ||||
| ->setTitleKey($key_title) | ->setTitleKey($key_title) | ||||
| ->setSummaryKey($key_summary); | ->setSummaryKey($key_summary); | ||||
| } | } | ||||
| /* -( Configuring the Parser )--------------------------------------------- */ | /* -( Configuring the Parser )--------------------------------------------- */ | ||||
| Show All 12 Lines | /* -( Configuring the Parser )--------------------------------------------- */ | ||||
| public function getViewer() { | public function getViewer() { | ||||
| return $this->viewer; | return $this->viewer; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task config | * @task config | ||||
| */ | */ | ||||
| public function setCommitMessageFields($fields) { | |||||
joshuaspence: Unless I am missing something, this should probably be `array $fields` | |||||
| assert_instances_of($fields, 'DifferentialCommitMessageField'); | |||||
| $fields = mpull($fields, null, 'getCommitMessageFieldKey'); | |||||
| $this->commitMessageFields = $fields; | |||||
| return $this; | |||||
| } | |||||
| /** | |||||
| * @task config | |||||
| */ | |||||
| public function getCommitMessageFields() { | |||||
| return $this->commitMessageFields; | |||||
| } | |||||
| /** | |||||
| * @task config | |||||
| */ | |||||
| public function setRaiseMissingFieldErrors($raise) { | public function setRaiseMissingFieldErrors($raise) { | ||||
| $this->raiseMissingFieldErrors = $raise; | $this->raiseMissingFieldErrors = $raise; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task config | * @task config | ||||
| Show All 34 Lines | /* -( Parsing Messages )--------------------------------------------------- */ | ||||
| /** | /** | ||||
| * @task parse | * @task parse | ||||
| */ | */ | ||||
| public function parseCorpus($corpus) { | public function parseCorpus($corpus) { | ||||
| $this->errors = array(); | $this->errors = array(); | ||||
| $label_map = $this->labelMap; | $label_map = $this->getLabelMap(); | ||||
| $key_title = $this->titleKey; | $key_title = $this->titleKey; | ||||
| $key_summary = $this->summaryKey; | $key_summary = $this->summaryKey; | ||||
| if (!$key_title || !$key_summary || ($label_map === null)) { | if (!$key_title || !$key_summary || ($label_map === null)) { | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| 'Expected %s, %s and %s to be set before parsing a corpus.', | 'Expected %s, %s and %s to be set before parsing a corpus.', | ||||
| 'labelMap', | 'labelMap', | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | /* -( Parsing Messages )--------------------------------------------------- */ | ||||
| /** | /** | ||||
| * @task parse | * @task parse | ||||
| */ | */ | ||||
| public function parseFields($corpus) { | public function parseFields($corpus) { | ||||
| $viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
| $text_map = $this->parseCorpus($corpus); | $text_map = $this->parseCorpus($corpus); | ||||
| $field_list = PhabricatorCustomField::getObjectFields( | $field_map = $this->getCommitMessageFields(); | ||||
| new DifferentialRevision(), | |||||
| DifferentialCustomField::ROLE_COMMITMESSAGE); | |||||
| $field_list->setViewer($viewer); | |||||
| $field_map = $field_list->getFields(); | |||||
| $field_map = mpull($field_map, null, 'getFieldKeyForConduit'); | |||||
| $result_map = array(); | $result_map = array(); | ||||
| foreach ($text_map as $field_key => $text_value) { | foreach ($text_map as $field_key => $text_value) { | ||||
| $field = idx($field_map, $field_key); | $field = idx($field_map, $field_key); | ||||
| if (!$field) { | if (!$field) { | ||||
| // This is a strict error, since we only parse fields which we have | // This is a strict error, since we only parse fields which we have | ||||
| // been told are valid. The caller probably handed us an invalid label | // been told are valid. The caller probably handed us an invalid label | ||||
| // map. | // map. | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| 'Parser emitted a field with key "%s", but no corresponding '. | 'Parser emitted a field with key "%s", but no corresponding '. | ||||
| 'field definition exists.', | 'field definition exists.', | ||||
| $field_key)); | $field_key)); | ||||
| } | } | ||||
| try { | try { | ||||
| $result = $field->parseValueFromCommitMessage($text_value); | $result = $field->parseFieldValue($text_value); | ||||
| $result_map[$field_key] = $result; | $result_map[$field_key] = $result; | ||||
| } catch (DifferentialFieldParseException $ex) { | } catch (DifferentialFieldParseException $ex) { | ||||
| $this->errors[] = pht( | $this->errors[] = pht( | ||||
| 'Error parsing field "%s": %s', | 'Error parsing field "%s": %s', | ||||
| $field->renderCommitMessageLabel(), | $field->renderCommitMessageLabel(), | ||||
| $ex->getMessage()); | $ex->getMessage()); | ||||
| } | } | ||||
| } | } | ||||
| if ($this->getRaiseMissingFieldErrors()) { | if ($this->getRaiseMissingFieldErrors()) { | ||||
| foreach ($field_map as $key => $field) { | foreach ($field_map as $key => $field) { | ||||
| try { | try { | ||||
| $field->validateCommitMessageValue(idx($result_map, $key)); | $field->validateFieldValue(idx($result_map, $key)); | ||||
| } catch (DifferentialFieldValidationException $ex) { | } catch (DifferentialFieldValidationException $ex) { | ||||
| $this->errors[] = pht( | $this->errors[] = pht( | ||||
| 'Invalid or missing field "%s": %s', | 'Invalid or missing field "%s": %s', | ||||
| $field->renderCommitMessageLabel(), | $field->renderCommitMessageLabel(), | ||||
| $ex->getMessage()); | $ex->getMessage()); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 19 Lines | /* -( Support Methods )---------------------------------------------------- */ | ||||
| public static function normalizeFieldLabel($label) { | public static function normalizeFieldLabel($label) { | ||||
| return phutil_utf8_strtolower($label); | return phutil_utf8_strtolower($label); | ||||
| } | } | ||||
| /* -( Internals )---------------------------------------------------------- */ | /* -( Internals )---------------------------------------------------------- */ | ||||
| private function getLabelMap() { | |||||
| if ($this->labelMap === null) { | |||||
| $field_list = $this->getCommitMessageFields(); | |||||
| $label_map = array(); | |||||
| foreach ($field_list as $field_key => $field) { | |||||
| $labels = $field->getFieldAliases(); | |||||
| $labels[] = $field->getFieldName(); | |||||
| foreach ($labels as $label) { | |||||
| $normal_label = self::normalizeFieldLabel($label); | |||||
| if (!empty($label_map[$normal_label])) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Field label "%s" is parsed by two custom fields: "%s" and '. | |||||
| '"%s". Each label must be parsed by only one field.', | |||||
| $label, | |||||
| $field_key, | |||||
| $label_map[$normal_label])); | |||||
| } | |||||
| $label_map[$normal_label] = $field_key; | |||||
| } | |||||
| } | |||||
| $this->labelMap = $label_map; | |||||
| } | |||||
| return $this->labelMap; | |||||
| } | |||||
| /** | /** | ||||
| * @task internal | * @task internal | ||||
| */ | */ | ||||
| private function buildLabelRegexp(array $label_map) { | private function buildLabelRegexp(array $label_map) { | ||||
| $field_labels = array_keys($label_map); | $field_labels = array_keys($label_map); | ||||
| foreach ($field_labels as $key => $label) { | foreach ($field_labels as $key => $label) { | ||||
| $field_labels[$key] = preg_quote($label, '/'); | $field_labels[$key] = preg_quote($label, '/'); | ||||
| } | } | ||||
| $field_labels = implode('|', $field_labels); | $field_labels = implode('|', $field_labels); | ||||
| $field_pattern = '/^(?P<field>'.$field_labels.'):(?P<text>.*)$/i'; | $field_pattern = '/^(?P<field>'.$field_labels.'):(?P<text>.*)$/i'; | ||||
| return $field_pattern; | return $field_pattern; | ||||
| } | } | ||||
| } | } | ||||
Unless I am missing something, this should probably be array $fields