Files
ulthon_admin/extend/base/common/command/admin/VersionBase.php
2025-03-28 18:08:21 +08:00

309 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace base\common\command\admin;
use app\common\tools\PathTools;
use think\App as ThinkApp;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class VersionBase extends Command
{
public const VERSION = 'v2.0.117';
public const PRODUCT_VERSION = '';
public const LAYUI_VERSION = 'v2.10.1';
public const COMMENT = [
'版本更新说明:',
'【新功能】',
'- 优化权限表格首列样式为不要换行',
'- 优化后台左上角logo标题的样式存在图片时再增加标题的空隙',
'- 页面增加radio自动通过预设值设置避免复杂的php或js渲染判断',
'- 优化更新逻辑设置think文件为必选文件',
'- 模型基类增加时间戳格式的通用处理方法',
'- 优化tableData组件支持读取原元素的style属性',
'- 优化错误信息提示不要自动关闭,需要用户点击空白区域关闭,方便用户仔细阅读和吸收弹框信息',
'- 优化curd临时文件生成时输出内容效果方便编辑器定位文件;',
'- 完善curd生成控制器时自动开启关联查询配置',
'- 新增默认从get中读取table的搜索参数',
'- 新增地图选点组件',
'- 优化tip样式',
'- 增加姓名字段;修改登录账号为可修改;',
'- 设置表格默认值为空避免显示null和undefined',
'- 生成表单时在添加页面默认读取get参数预设值',
'- 修改生成发布说明的标题级别',
'【修复】',
'- 修复地图重复渲染的问题',
'- 修复视图范围类组件处理变量时没有兼容null值的问题',
'- 修复自动从url读取table搜索参数兼容性问题',
'- 修复确认框取消时会自动关闭当前页面的问题',
'- 修复接口模式不能退出的问题',
'【重构】',
'- 版本内容整理使用统一的类型配置',
];
protected const COMMIT_TYPES = [
'feat' => '新功能',
'fix' => '修复',
'docs' => '文档',
'style' => '样式',
'refactor' => '重构',
'perf' => '性能优化',
'test' => '测试',
'build' => '构建',
'ci' => '持续集成',
'chore' => '其他',
'revert' => '回退',
];
protected function configure()
{
// 指令配置
$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的版本号');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
if (!empty(static::PRODUCT_VERSION)) {
$output->info('当前版本号为:' . static::PRODUCT_VERSION);
}
$output->info('当前ulthon_admin版本号为' . static::VERSION);
$output->info('当前Layui版本号为' . static::LAYUI_VERSION);
$output->info('当前ThinkPHP版本号为' . ThinkApp::VERSION);
$output->writeln('当前的修改说明:');
$output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
foreach (static::COMMENT as $comment) {
$output->info($comment);
}
$output->writeln('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<');
$output->highlight('代码托管地址https://gitee.com/ulthon/ulthon_admin');
$output->highlight('开发文档地址http://doc.ulthon.com/home/read/ulthon_admin/home.html');
$is_push_tag = $input->hasOption('push-tag');
if ($is_push_tag) {
$this->pushTag();
}
$is_generate_comment = $input->hasOption('generate-comment');
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()
{
$input = $this->input;
$output = $this->output;
$output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
$version = static::VERSION;
if (!empty(static::PRODUCT_VERSION)) {
$version = static::PRODUCT_VERSION;
}
// 将提交信息写入临时文件
$comment = implode("\n", static::COMMENT);
$output->info('生成标签:' . $version);
$output->info('标签描述:' . $comment);
// 使用项目的临时文件路径生成方法
$tempFile = PathTools::tempBuildPath('git_tag_message_' . uniqid() . '.txt');
file_put_contents($tempFile, $comment);
// 使用 -F 参数从文件读取提交信息
exec("git tag -a $version -F \"$tempFile\"");
// 删除临时文件
if (file_exists($tempFile)) {
unlink($tempFile);
}
$output->info('推送到远程仓库');
exec('git push --tags');
}
/**
* 生成版本更新说明
* 读取自上次tag到现在所有的提交说明.
* @return string
*/
public function generateComment()
{
$this->output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
// 获取最新的tag
$lastTag = shell_exec('git describe --tags --abbrev=0');
$lastTag = trim($lastTag);
// 获取从最新tag到现在的所有提交
$commits = shell_exec("git log {$lastTag}..HEAD --pretty=format:\"%s\"");
if (empty($commits)) {
return '暂无更新说明';
}
$commits = explode("\n", $commits);
// 按类型分组提交
$groupedCommits = [];
foreach ($commits as $commit) {
$matched = false;
foreach (static::COMMIT_TYPES as $type => $desc) {
if (preg_match("/^{$type}:/i", $commit)) {
$message = preg_replace("/^{$type}:/i", '', $commit);
$groupedCommits[$desc][] = trim($message);
$matched = true;
break;
}
}
// 如果没有匹配到任何类型,归类为"其他"
if (!$matched) {
$groupedCommits['其他'][] = trim($commit);
}
}
// 生成更新说明
$comment = "版本更新说明:\n";
foreach ($groupedCommits as $type => $messages) {
$comment .= "\n{$type}\n";
foreach ($messages as $message) {
$comment .= "- {$message}\n";
}
}
$this->output->writeln($comment);
// 生成数组格式文件
$comment_arr = explode("\n", $comment);
$comment_arr = array_filter($comment_arr, function ($item) {
return !empty($item);
});
$comment_arr = array_map(function ($item) {
return "'" . addslashes(trim($item)) . "',";
}, $comment_arr);
$comment_arr_code = implode("\n", $comment_arr);
$tmp_comment_file = PathTools::tempBuildPath('commit_comment.php');
file_put_contents($tmp_comment_file, "<?php\nreturn [\n" . $comment_arr_code . "\n];");
$this->output->info('已生成版本更新代码:' . $tmp_comment_file);
$tmp_comment_markdown_file = PathTools::tempBuildPath('commit_comment.md');
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);
// 按类型分组提交
$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 (static::COMMIT_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);
}
}