diff --git a/extend/base/common/command/admin/VersionBase.php b/extend/base/common/command/admin/VersionBase.php index 7e92536..4d186e7 100644 --- a/extend/base/common/command/admin/VersionBase.php +++ b/extend/base/common/command/admin/VersionBase.php @@ -51,6 +51,8 @@ class VersionBase extends Command // 指令配置 $this->setName('admin:version') ->addOption('generate-comment', null, Option::VALUE_NONE, '使用git命令生成说明文件') + ->addOption('generate-release', null, Option::VALUE_NONE, '使用git命令生成发布说明文件') + ->addOption('release-from-tag', null, Option::VALUE_OPTIONAL, '从指定版本开始生成说明文件') ->addOption('push-tag', null, Option::VALUE_NONE, '使用git命令生成tag并推送') ->setDescription('查看当前ulthon_admin的版本号'); } @@ -85,6 +87,12 @@ class VersionBase extends Command if ($is_generate_comment) { $this->generateComment(); } + + $is_generate_release = $input->hasOption('generate-release'); + if ($is_generate_release) { + $fromTag = $input->getOption('release-from-tag'); + $this->generateRelease($fromTag); + } } protected function pushTag() @@ -202,4 +210,112 @@ class VersionBase extends Command file_put_contents($tmp_comment_markdown_file, $comment); $this->output->info('已生成版本更新Markdown:' . $tmp_comment_markdown_file); } + + /** + * 生成发布说明文件 + * 从指定版本开始生成发布说明. + * @param string|null $fromTag 起始版本号,如果为空则使用最近的tag + * @return void + */ + public function generateRelease($fromTag = null) + { + $output = $this->output; + + // 如果没有指定起始版本,则获取最近的tag + if (empty($fromTag)) { + $fromTag = shell_exec('git describe --tags --abbrev=0'); + $fromTag = trim($fromTag); + $output->info('未指定起始版本,使用最近的tag: ' . $fromTag); + } else { + $output->info('从指定版本开始生成发布说明: ' . $fromTag); + } + + // 获取当前版本 + $currentVersion = static::VERSION; + if (!empty(static::PRODUCT_VERSION)) { + $currentVersion = static::PRODUCT_VERSION; + } + + // 获取从指定tag到现在的所有提交,包含提交哈希和提交日期 + $commits = shell_exec("git log {$fromTag}..HEAD --pretty=format:\"%h %ad %s\" --date=short"); + + if (empty($commits)) { + $output->warning('从 ' . $fromTag . ' 到现在没有任何提交'); + return; + } + + $commits = explode("\n", $commits); + + // 定义提交类型 + $types = [ + 'feat' => '新功能', + 'fix' => '修复', + 'docs' => '文档', + 'style' => '样式', + 'refactor' => '重构', + 'perf' => '性能优化', + 'test' => '测试', + 'build' => '构建', + 'ci' => '持续集成', + 'chore' => '其他', + 'revert' => '回退', + ]; + + // 按类型分组提交 + $groupedCommits = []; + foreach ($commits as $commit) { + $matched = false; + // 提取提交哈希和日期 + preg_match('/^([a-f0-9]+)\s(\d{4}-\d{2}-\d{2})\s(.+)$/', $commit, $matches); + + if (count($matches) >= 4) { + $hash = $matches[1]; + $date = $matches[2]; + $message = $matches[3]; + + foreach ($types as $type => $desc) { + if (preg_match("/^{$type}:/i", $message)) { + $cleanMessage = preg_replace("/^{$type}:/i", '', $message); + $groupedCommits[$desc][] = [ + 'message' => trim($cleanMessage), + 'hash' => $hash, + 'date' => $date + ]; + $matched = true; + break; + } + } + + // 如果没有匹配到任何类型,归类为"其他" + if (!$matched) { + $groupedCommits['其他'][] = [ + 'message' => trim($message), + 'hash' => $hash, + 'date' => $date + ]; + } + } + } + + // 生成发布说明 + $releaseTitle = "# {$currentVersion} 发布说明\n\n"; + $releaseDate = '发布日期: ' . date('Y-m-d') . "\n\n"; + $releaseContent = "本次发布包含了从 {$fromTag} 到 {$currentVersion} 的所有更新。\n\n"; + + foreach ($groupedCommits as $type => $messages) { + $releaseContent .= "## {$type}\n\n"; + foreach ($messages as $item) { + $releaseContent .= "- [{$item['date']}] {$item['message']} (#{$item['hash']})\n"; + } + $releaseContent .= "\n"; + } + + $release = $releaseTitle . $releaseDate . $releaseContent; + + // 生成发布说明文件 + $releaseFile = PathTools::tempBuildPath("release_{$currentVersion}.md"); + file_put_contents($releaseFile, $release); + $output->info('已生成发布说明文件: ' . $releaseFile); + } + }