diff --git a/src/Changelog.php b/src/Changelog.php index e2457ef..1025444 100644 --- a/src/Changelog.php +++ b/src/Changelog.php @@ -242,7 +242,7 @@ public function generate(InputInterface $input, SymfonyStyle $output): int // Get all commits information $commits = []; foreach ($commitsRaw as $commitRaw) { - $commit = new Commit\Conventional($commitRaw); + $commit = Commit\Conventional::fromCommit($commitRaw); // Not a conventional commit if (!$commit->isValid()) { @@ -259,7 +259,7 @@ public function generate(InputInterface $input, SymfonyStyle $output): int } // Add commit if (!$ignore) { - $commits[] = new Commit\Conventional($commit); + $commits[] = $commit; } } diff --git a/src/Commit/Commit.php b/src/Commit/Commit.php new file mode 100644 index 0000000..351ed2c --- /dev/null +++ b/src/Commit/Commit.php @@ -0,0 +1,218 @@ +setRaw($raw); + } + + /** + * From array. + * + * @throws \Exception + */ + public function fromArray(array $array) + { + if (isset($array['raw'])) { + $this->setRaw($array['raw']); + } + if (isset($array['hash'])) { + $this->setHash($array['hash']); + } + if (isset($array['authorName'])) { + $this->setAuthorName($array['authorName']); + } + if (isset($array['authorEmail'])) { + $this->setAuthorEmail($array['authorEmail']); + } + if (isset($array['authorDate'])) { + $date = new DateTime($array['authorDate']); + $this->setAuthorDate($date); + } + if (isset($array['committerName'])) { + $this->setCommitterName($array['committerName']); + } + if (isset($array['committerEmail'])) { + $this->setCommitterEmail($array['committerEmail']); + } + if (isset($array['committerDate'])) { + $date = new DateTime($array['committerDate']); + $this->setCommitterDate($date); + } + + return $this; + } + + /** + * Check if is valid SHA-1. + */ + protected function isValidHash(string $hash) + { + return (bool)preg_match('/^[0-9a-f]{40}$/i', $hash); + } + + public function setRaw(string $raw): self + { + $this->raw = $raw; + + return $this; + } + + public function setHash(string $hash): self + { + if ($this->isValidHash($hash)) { + $this->hash = $hash; + } + + return $this; + } + + public function getRaw(): ?string + { + return $this->raw; + } + + public function getHash(): ?string + { + return $this->hash; + } + + public function getShortHash(): string + { + return substr($this->hash, 0, 6); + } + + public function getAuthorDate(): DateTime + { + return $this->authorDate; + } + + public function setAuthorDate(DateTime $authorDate): Commit + { + $this->authorDate = $authorDate; + + return $this; + } + + public function getAuthorName(): string + { + return $this->authorName; + } + + public function setAuthorName(string $authorName): Commit + { + $this->authorName = $authorName; + + return $this; + } + + public function getAuthorEmail(): string + { + return $this->authorEmail; + } + + public function setAuthorEmail(string $authorEmail): Commit + { + $this->authorEmail = $authorEmail; + + return $this; + } + + public function getCommitterDate(): DateTime + { + return $this->committerDate; + } + + public function setCommitterDate(DateTime $committerDate): Commit + { + $this->committerDate = $committerDate; + + return $this; + } + + public function getCommitterName(): string + { + return $this->committerName; + } + + public function setCommitterName(string $committerName): Commit + { + $this->committerName = $committerName; + + return $this; + } + + public function getCommitterEmail(): string + { + return $this->committerEmail; + } + + public function setCommitterEmail(string $committerEmail): Commit + { + $this->committerEmail = $committerEmail; + + return $this; + } + + public function __toString(): string + { + return $this->getRaw(); + } +} diff --git a/src/Commit/Conventional.php b/src/Commit/Conventional.php index 3a3f2cc..cf753e0 100644 --- a/src/Commit/Conventional.php +++ b/src/Commit/Conventional.php @@ -3,20 +3,12 @@ namespace ConventionalChangelog\Commit; use ConventionalChangelog\Helper\Formatter; -use ConventionalChangelog\Type\Stringable; -class Conventional implements Stringable +class Conventional extends Commit { protected const PATTERN_HEADER = "/^(?'type'[a-z]+)(\((?'scope'.+)\))?(?'important'[!]?)[:][[:blank:]](?'description'.+)/iums"; protected const PATTERN_FOOTER = "/(?'token'^([a-z0-9_-]+|BREAKING[[:blank:]]CHANGES?))(?'value'([:][[:blank:]]|[:]?[[:blank:]][#](?=\w)).*?)$/iums"; - /** - * Raw content. - * - * @var string - */ - protected $raw; - /** * Sha hash. * @@ -64,38 +56,21 @@ class Conventional implements Stringable */ protected $footers = []; - public function __construct(string $commit = '') + public function __construct(?string $commit = null) { + parent::__construct($commit); + // New commit or empty commit if (empty($commit)) { return; } - $raw = Formatter::clean($commit); - $this->setRaw($raw); - // Not parsable if (!$this->isValid()) { return; } - $rows = explode("\n", $this->raw); - $count = count($rows); - // Commit info - $hash = trim($rows[$count - 1]); - if ($this->isValidHash($hash)) { - $this->hash = $hash; - } - $header = $rows[0]; - $message = ''; - // Get message - foreach ($rows as $i => $row) { - if ($i !== 0 && $i !== $count) { - $message .= $row . "\n"; - } - } - $this->parseHeader($header); - $this->parseMessage($message); + $this->__wakeup(); } /** @@ -132,11 +107,15 @@ protected function parseMessage(string $message) } /** - * Check if is valid SHA-1. + * From commit. + * + * @return self */ - protected function isValidHash(string $hash) + public static function fromCommit(Commit $commit) { - return (bool)preg_match('/^[0-9a-f]{40}$/i', $hash); + return unserialize( + preg_replace('/^O:\d+:"[^"]++"/', 'O:' . strlen(__CLASS__) . ':"' . __CLASS__ . '"', serialize($commit)) + ); } /** @@ -147,21 +126,6 @@ public function isValid(): bool return (bool)preg_match(self::PATTERN_HEADER, $this->raw); } - public function getRaw(): ?string - { - return $this->raw; - } - - public function getHash(): ?string - { - return $this->hash; - } - - public function getShortHash(): string - { - return substr($this->hash, 0, 6); - } - public function getType(): Type { return $this->type; @@ -246,23 +210,6 @@ public function getMessage() return $this->body . "\n\n" . $footer; } - /** - * @return Conventional - */ - public function setRaw(string $raw): self - { - $this->raw = $raw; - - return $this; - } - - public function setHash(string $hash): self - { - $this->hash = $hash; - - return $this; - } - public function setType(string $type): self { $this->type = new Type($type); @@ -305,6 +252,26 @@ public function setFooters(array $footers): self return $this; } + public function __wakeup() + { + $rows = explode("\n", $this->raw); + $count = count($rows); + // Commit info + $hash = trim($rows[$count - 1]); + $this->setHash($hash); + + $header = $rows[0]; + $message = ''; + // Get message + foreach ($rows as $i => $row) { + if ($i !== 0 && $i !== $count) { + $message .= $row . "\n"; + } + } + $this->parseHeader($header); + $this->parseMessage($message); + } + public function __toString(): string { $header = $this->getHeader(); diff --git a/src/Helper/Git.php b/src/Helper/Git.php index b465efa..149d7da 100644 --- a/src/Helper/Git.php +++ b/src/Helper/Git.php @@ -2,6 +2,7 @@ namespace ConventionalChangelog\Helper; +use ConventionalChangelog\Commit\Commit; use DateTime; class Git @@ -92,11 +93,37 @@ public static function getRemoteUrl(): string */ public static function getCommits(string $options = ''): array { - $commits = self::run("git log --pretty=format:'%B%H" . self::$delimiter . "' {$options}") . "\n"; - $commitsArray = explode(self::$delimiter . "\n", $commits); + $commits = []; + $shortcodes = [ + 'raw' => '%B', + 'hash' => '%H', + 'authorName' => '%aN', + 'authorEmail' => '%aE', + 'authorDate' => '%aI', + 'committerName' => '%cN', + 'committerEmail' => '%cE', + 'committerDate' => '%cI', + ]; + + $format = ''; + foreach ($shortcodes as $key => $value) { + $format .= "[{$key}]{$value}[/{$key}]"; + } + $format .= self::$delimiter; + $commitsLogs = self::run("git log --pretty=format:'" . $format . "' {$options}") . "\n"; + + $commitsArray = explode(self::$delimiter . "\n", $commitsLogs); array_pop($commitsArray); - return $commitsArray; + $shortcodesKeys = array_keys($shortcodes); + foreach ($commitsArray as $commitRaw) { + $parse = self::parseShortcodes($commitRaw, $shortcodesKeys); + $commit = new Commit(); + $commit->fromArray($parse); + $commits[] = $commit; + } + + return $commits; } /** @@ -144,4 +171,28 @@ public static function tag(string $name) { return exec("git tag {$name}"); } + + /** + * Parse shortcode. + * + * @param $content + * @param $shortcodes + * + * @return array + */ + protected static function parseShortcodes($content, $shortcodes) + { + $result = []; + foreach ($shortcodes as $key) { + $result[$key] = null; + $key = preg_quote($key, '/'); + $pattern = "/\[[\s]*" . $key . "[\s]*\](.+?)\[[\s]*\/[\s]*" . $key . "[\s]*\]/si"; + preg_match_all($pattern, $content, $match); + if (count($match) > 0 && !empty($match[0]) && isset($match[1][0])) { + $result[$key] = $match[1][0]; + } + } + + return $result; + } }