diff --git a/src/parser/PhutilGnupgCommit.php b/src/parser/PhutilGnupgCommit.php index ccceeab..202254c 100644 --- a/src/parser/PhutilGnupgCommit.php +++ b/src/parser/PhutilGnupgCommit.php @@ -1,220 +1,232 @@ <?php /** * Parse GnuPG-style commit messages. */ final class PhutilGnupgCommit extends Phobject { private $corpus; private $title; private $keywords; # Array private $changelog; # Array of lines private $summary; # Array of lines private $testplan; # Array of lines private $extra; # Ass. array of extra fields private $valid; public function __construct($corpus) { if ($corpus instanceof PhutilGnupgCommit) { $this->corpus = $corpus->corpus; $this->title = $corpus->title; $this->keywords = $corpus->keywords; $this->changelog = $corpus->changelog; $this->summary = $corpus->summary; $this->testplan = $corpus->testplan; $this->extra = $corpus->extra; $this->valid = $corpus->valid; return; } $this->setCommitMessage((string)$corpus); } /** Determine if the commit message was parsed correctly. * * @return bool True if commit message was parsed. */ public function isValid() { return $this->valid; } /** * Set commit message. * * @param string Commit message. */ public function setCommitMessage($corpus) { $result = $this->process_message($corpus); $this->title = $result['title']; $this->keywords = $result['keywords']; $this->changelog = $result['changelog']; $this->summary = $result['summary']; $this->testplan = $result['testplan']; $this->extra = $result['extra']; $this->valid = true; } /** * Get message parsed for diffusion controller. * * @return string Formatted commit message. */ public function getDiffusionCommitMessage() { $message = array(); if ($this->title != "") { $message[] = $this->title; $message[] = ""; } if (count($this->changelog) > 0) { $message[] = "```"; foreach ($this->changelog as $line) { $message[] = $line; } $message[] = "```"; $message[] = ""; } if (count($this->summary) > 0) { foreach ($this->summary as $line) { $message[] = $line; } $message[] = ""; } if (count($this->testplan) > 0) { foreach ($this->testplan as $line) { $message[] = $line; } $message[] = ""; } if (count($this->extra) > 0) { foreach ($this->extra as $key => $value) { + $value = $this->transmogrify_extra($key, $value); $message[] = "* " . $key . ": " . $value; } $message[] = ""; } return join("\n", $message); } + private function transmogrify_extra($key, $value) + { + $key = strtolower($key); + if ($key == "gnupg-bug-id") { + $value = preg_replace("/\b(\d+)\b/", "T$1", $value); + } else if ($key == "debian-bug-id") { + $value = preg_replace("/\b(\d+)\b/", "[[https://bugs.debian.org/$1|#$1]]", $value); + } + return $value; + } + private function process_message($message) { $valid_extra_fields = array("signed-off-by", "gnupg-bug-id", "fixes-commit", "reported-by", "debian-bug-id", "suggested-by", "regression-due-to", "co-authored-by", "proofread-by", "see-also", "some-comments-by", "hat-tip-to"); # We want at least two lines (simplifies the logic). $message = $message . "\n\n"; $message_lines = explode("\n", $message); $first_line = array_shift($message_lines); $keywords = array(); $title = "(no title)"; $changelog = array(); $summary = array(); $testplan = array(); $extra = array(); if (strncmp($first_line, "*", 1) == 0 || strncmp($first_line, "(", 1) == 0 || $message_lines[0] != "") { # No title line. array_unshift($message_lines, $first_line); } else { $title = $first_line; $blank = array_shift($message_lines); # Disabled for now to keep things simple. # if (strpos($first_line, ":") !== false) { # list($keywords, $title) = explode(':', $first_line, 2); # $keywords = explode(',', $keywords); # $keywords = array_map('trim', $keywords); # } # TODO: Verify that the keywords are all valid. } # ChangeLog style entries. $in_par = false; do { $line = array_shift($message_lines); if ($line === null) { break; } $is_separator = preg_match('/^\s*--\s*$/', $line); $is_blank = preg_match('/^\s*$/', $line); $is_change = preg_match('/^[*(]/', $line); if ($is_separator) { break; } else if ($is_blank) { $in_par = false; } else if ($in_par) { $changelog[] = $line; } else if ($is_change) { $changelog[] = $line; $in_par = true; } else { # Not $in_par, unexpected input. array_unshift($message_lines, $line); break; } } while (true); # Summary (aka test plan for now) and extra fields. $add_blank = false; $at_beginning = true; do { $line = array_shift($message_lines); if ($line === null) { break; } $is_blank = preg_match('/^\s*$/', $line); $is_extra = preg_match('/^([-a-zA-Z]+):\s*(.*)$/', $line, $match); $key = null; $val = null; if ($is_extra) { $key = $match[1]; $val = $match[2]; } if (! in_array(strtolower($key), $valid_extra_fields)) { $is_extra = false; } if ($is_extra) { $extra[$key] = $val; } else if ($is_blank) { $add_blank = true; } else { if ($add_blank) { if (! $at_beginning) { $summary[] = ""; } $add_blank = false; } $summary[] = $line; $at_beginning = false; } } while (true); # Post-processing. $title = trim($title); $result['title'] = $title; $result['keywords'] = $keywords; $result['changelog'] = $changelog; $result['summary'] = $summary; $result['testplan'] = $testplan; $result['extra'] = $extra; return $result; } }