Browse Source

移除旧的 Shell 和 PowerShell 脚本,改为使用 Go 程序生成构建数据

删除了 `get_date.sh`、`get_git.sh` 等 Shell 脚本和对应的 PowerShell 脚本,新增了 Go 实现的生成逻辑,简化了构建流程并提高了跨平台兼容性。同时调整了生成文件的后缀为 `.dat.ignore` 以便更好地管理忽略规则。
SongZihuan 5 days ago
parent
commit
5ba9ab4e00

+ 13 - 4
.github/workflows/go-tag-release.yml

@@ -8,7 +8,7 @@ on:
       - main
       - main
       - master
       - master
     tags:
     tags:
-      - '*'   # 匹配所有标签
+      - 'v*'   # 匹配 'v' 开头的标签
   pull_request:
   pull_request:
     types:
     types:
       - opened
       - opened
@@ -100,6 +100,9 @@ jobs:
         run: |
         run: |
           GOOS=linux GOARCH=amd64 go build -o "${{ github.workspace }}/output/linux_amd64_catv1" -trimpath -ldflags='-s -w -extldflags "-static"' github.com/SongZihuan/BackendServerTemplate/src/cmd/catv1
           GOOS=linux GOARCH=amd64 go build -o "${{ github.workspace }}/output/linux_amd64_catv1" -trimpath -ldflags='-s -w -extldflags "-static"' github.com/SongZihuan/BackendServerTemplate/src/cmd/catv1
 
 
+      - name: Copy Release Info
+        run: copy "${{ github.workspace }}/release_info.md.ignore" "${{ github.workspace }}/output/release_info.md"
+
       - name: List build directory
       - name: List build directory
         run: |
         run: |
           ls -l "${{ github.workspace }}/output"
           ls -l "${{ github.workspace }}/output"
@@ -181,6 +184,14 @@ jobs:
         with:
         with:
           fetch-depth: 0 # 获取所有历史记录以便能够创建标签
           fetch-depth: 0 # 获取所有历史记录以便能够创建标签
 
 
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: '1.23.4' # 根据需要指定Go版本
+
+      - name: Go generate
+        run: GOOS=linux GOARCH=amd64 go generate ./...
+
       - name: Extract tag name
       - name: Extract tag name
         id: extract_tag
         id: extract_tag
         run: |
         run: |
@@ -210,9 +221,7 @@ jobs:
           artifacts: "${{ github.workspace }}/output/linux_amd64_lionv1,${{ github.workspace }}/output/linux_amd64_tigerv1,${{ github.workspace }}/output/linux_amd64_catv1,${{ github.workspace }}/output/windows_amd64_lionv1.exe,${{ github.workspace }}/output/windows_amd64_tigerv1.exe,${{ github.workspace }}/output/windows_amd64_catv1.exe"
           artifacts: "${{ github.workspace }}/output/linux_amd64_lionv1,${{ github.workspace }}/output/linux_amd64_tigerv1,${{ github.workspace }}/output/linux_amd64_catv1,${{ github.workspace }}/output/windows_amd64_lionv1.exe,${{ github.workspace }}/output/windows_amd64_tigerv1.exe,${{ github.workspace }}/output/windows_amd64_catv1.exe"
           artifactErrorsFailBuild: true
           artifactErrorsFailBuild: true
           allowUpdates: false
           allowUpdates: false
-          body: |
-            新版本 ${{  steps.extract_tag.outputs.tag  }} 发布啦!
-            快来体验吧!
+          bodyFile: "${{ github.workspace }}/output/release_info.md"
           generateReleaseNotes: true
           generateReleaseNotes: true
           makeLatest: "legacy"
           makeLatest: "legacy"
           tag: "${{  github.ref  }} "
           tag: "${{  github.ref  }} "

+ 2 - 9
.gitignore

@@ -20,12 +20,5 @@ test_self
 
 
 output
 output
 
 
-build_date.txt
-
-commit_data.txt
-tag_data.txt
-tag_commit_data.txt
-
-random_data.txt
-
-release_info.md
+# auto write by go generate
+*.ignore

+ 3 - 0
CHANGELOG.md

@@ -14,6 +14,7 @@
 - 强制所以`cmd`下的可执行程序包都必须显示导入`prerun`包。
 - 强制所以`cmd`下的可执行程序包都必须显示导入`prerun`包。
 - 强制`prerun`包必须显示导入`global`包。
 - 强制`prerun`包必须显示导入`global`包。
 - 默认导入`time/tzdata`时区数据包,除非添加`systemtzdata`标签,表示使用操作系统自带的数据包。
 - 默认导入`time/tzdata`时区数据包,除非添加`systemtzdata`标签,表示使用操作系统自带的数据包。
+- 在 `go gerenate` 中添加发布信息(`release_info.md`),但因为该文件需要被忽略,因此修改为:`release_info.md.ignore`。
 
 
 ### 修改
 ### 修改
 
 
@@ -29,6 +30,7 @@
 
 
 - 完善时区系统,获取本地时间时可以读取到`IANA`时区信息。
 - 完善时区系统,获取本地时间时可以读取到`IANA`时区信息。
 - 重构了退出机制。将`main`程序移到`command`程序,将原本的`os.Exit`替换成`return`一个`ExitCode`,最后在`main`函数在使用`os.Exit`退出程序。有效的解决了以前直接在`main`使用`os.Exit`导致`defer`函数无法释放。
 - 重构了退出机制。将`main`程序移到`command`程序,将原本的`os.Exit`替换成`return`一个`ExitCode`,最后在`main`函数在使用`os.Exit`退出程序。有效的解决了以前直接在`main`使用`os.Exit`导致`defer`函数无法释放。
+- 将 `go generate` 从原本的 `Shell` 脚本(`.sh`和`.ps1`)换成由 `go run` 直接执行的 `.go` 程序。 同时,数据文件以 `.dat` 作为文件后缀(除特殊的 `VERSION`,`NAME`,`REPORT`,`LICENSE`,`ENV_PREFIX`),并且需要忽略的文件以 `.ignore`  作为后缀。
 
 
 ### 文档
 ### 文档
 
 
@@ -42,6 +44,7 @@
 ### 其他
 ### 其他
 
 
 - 调整`GitHub`的`PR`模板。
 - 调整`GitHub`的`PR`模板。
+- 使用`GitHub Action`流水线创建`Release`时使用`markdown`文件:`release_info.md`。
 
 
 ## [0.10.0] - 2025-04-23 Asia/Shanghai
 ## [0.10.0] - 2025-04-23 Asia/Shanghai
 
 

+ 1 - 7
get_date_posix.go → get_data.go

@@ -2,12 +2,6 @@
 // Use of this source code is governed by a MIT-style
 // Use of this source code is governed by a MIT-style
 // license that can be found in the LICENSE file.
 // license that can be found in the LICENSE file.
 
 
-//go:build !windows
-
-//go:generate /bin/bash ./get_date.sh
-
-//go:generate /bin/bash ./get_git.sh
-
-//go:generate /bin/bash ./get_random.sh
+//go:generate go run github.com/SongZihuan/BackendServerTemplate/tool/generate
 
 
 package resource
 package resource

+ 0 - 6
get_date.ps1

@@ -1,6 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-$timestamp = [math]::Floor([decimal]((Get-Date).ToUniversalTime() | Get-Date -UFormat %s))
-Set-Content -Path "build_date.txt" -Value $timestamp

+ 0 - 5
get_date.sh

@@ -1,5 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-date '+%s' > build_date.txt

+ 0 - 13
get_date_win32.go

@@ -1,13 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-//go:build windows
-
-//go:generate powershell -ExecutionPolicy RemoteSigned ./get_date.ps1
-
-//go:generate powershell -ExecutionPolicy RemoteSigned ./get_git.ps1
-
-//go:generate powershell -ExecutionPolicy RemoteSigned ./get_random.ps1
-
-package resource

+ 0 - 27
get_git.ps1

@@ -1,27 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-if (Test-Path -Path ".\.git" -PathType Container) {
-    $last_commit = git rev-parse HEAD 2>$null
-    $last_tag = git describe --tags --abbrev=0 2>$null
-
-    if (-not [string]::IsNullOrEmpty($last_tag)) {
-        $last_tag_commit = git rev-list -n 1 $last_tag 2>$null
-
-        Set-Content -Path "commit_data.txt" -Value $last_commit -Encoding UTF8
-        Set-Content -Path "tag_data.txt" -Value $last_tag -Encoding UTF8
-        Set-Content -Path "tag_commit_data.txt" -Value $last_tag_commit -Encoding UTF8
-    } else {
-        Set-Content -Path "commit_data.txt" -Value $last_commit -Encoding UTF8
-        New-Item -Path "tag_data.txt" -ItemType File -Force
-        New-Item -Path "tag_commit_data.txt" -ItemType File -Force
-    }
-} else {
-    New-Item -Path "commit_data.txt" -ItemType File -Force
-    New-Item -Path "tag_data.txt" -ItemType File -Force
-    New-Item -Path "tag_commit_data.txt" -ItemType File -Force
-}
-
-# 创建 VERSION 文件
-New-Item -Path "VERSION" -ItemType File -Force

+ 0 - 26
get_git.sh

@@ -1,26 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-if [ -d "./.git" ]; then
-    last_commit="$(git rev-parse HEAD 2>/dev/null)"
-    last_tag="$(git describe --tags --abbrev=0 2>/dev/null)"
-
-    if [ -n "$last_tag" ]; then
-      last_tag_commit="$(git rev-list -n 1 "$last_tag" 2>/dev/null)"
-
-      echo "$last_commit" > commit_data.txt
-      echo "$last_tag" > tag_data.txt
-      echo "$last_tag_commit" > tag_commit_data.txt
-    else
-      echo "$last_commit" > commit_data.txt
-      touch tag_data.txt
-      touch tag_commit_data.txt
-    fi
-else
-    touch commit_data.txt
-    touch tag_data.txt
-    touch tag_commit_data.txt
-fi
-
-touch "VERSION"

+ 0 - 10
get_random.ps1

@@ -1,10 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-$characters = 'abcdefghijklmnopqrstuvwxyz0123456789'
-$length = 40
-
-$randomString = -join (1..$length | ForEach-Object { $characters[(Get-Random -Maximum $characters.Length)] })
-
-Set-Content -Path "random_data.txt" -Value $randomString -Encoding UTF8

+ 0 - 7
get_random.sh

@@ -1,7 +0,0 @@
-# Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file.
-
-length=40
-randomString=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w $length | head -n 1)
-echo "$randomString" > random_data.txt

+ 5 - 5
resource.go

@@ -27,21 +27,21 @@ var Name string
 //go:embed ENV_PREFIX
 //go:embed ENV_PREFIX
 var EnvPrefix string
 var EnvPrefix string
 
 
-//go:embed build_date.txt
+//go:embed build_date.dat.ignore
 var buildDateTxt string
 var buildDateTxt string
 
 
 var BuildTime time.Time
 var BuildTime time.Time
 
 
-//go:embed commit_data.txt
+//go:embed commit_data.dat.ignore
 var GitCommitHash string
 var GitCommitHash string
 
 
-//go:embed tag_data.txt
+//go:embed tag_data.dat.ignore
 var GitTag string
 var GitTag string
 
 
-//go:embed tag_commit_data.txt
+//go:embed tag_commit_data.dat.ignore
 var GitTagCommitHash string
 var GitTagCommitHash string
 
 
-//go:embed random_data.txt
+//go:embed random_data.dat.ignore
 var randomData string
 var randomData string
 
 
 func init() {
 func init() {

+ 46 - 15
tool/generate/basefile/basefile.go

@@ -4,75 +4,106 @@
 
 
 package basefile
 package basefile
 
 
-import "github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
+import (
+	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
+	"log"
+)
 
 
 const (
 const (
-	FileVersion   = "./VERSION"
-	FileLicense   = "./LICENSE"
-	FileReport    = "./REPORT"
-	FileName      = "./NAME"
-	FileEnvPrefix = "./ENV_PREFIX"
-
-	FileBuildDateTxt  = "./build_date.txt"
-	FileCommitDateTxt = "./commit_data.txt"
-	FileTagDataTxt    = "./tag_data.txt"
-	FileTagCommitData = "./tag_commit_data.txt"
-	FileRandomData    = "./random_data.txt"
-
-	FileReleaseInfoMD = "./release_info.md"
+	FileIgnoreExt    = ".ignore"
+	GitIgnoreExtFlag = "*" + FileIgnoreExt
 )
 )
 
 
-func CreateBaseFile() (err error) {
+const (
+	FileVersion    = "./VERSION"
+	FileLicense    = "./LICENSE"
+	FileReport     = "./REPORT"
+	FileName       = "./NAME"
+	FileEnvPrefix  = "./ENV_PREFIX"
+	FileSystemYaml = "./SERVICE.yaml"
+
+	FileBuildDateTxt  = "./build_date.dat" + FileIgnoreExt
+	FileCommitDateTxt = "./commit_data.dat" + FileIgnoreExt
+	FileTagDataTxt    = "./tag_data.dat" + FileIgnoreExt
+	FileTagCommitData = "./tag_commit_data.dat" + FileIgnoreExt
+	FileRandomData    = "./random_data.dat" + FileIgnoreExt
+
+	FileReleaseInfoMD = "./release_info.md" + FileIgnoreExt
+
+	FileGitIgnore = "./.gitignore"
+)
+
+func TouchBaseFile() (err error) {
+	log.Println("generate: touch base file")
+	defer log.Println("generate: touch base file finish")
+
+	log.Printf("generate: touch file %s\n", FileVersion)
 	err = fileutils.Touch(FileVersion)
 	err = fileutils.Touch(FileVersion)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileLicense)
 	err = fileutils.Touch(FileLicense)
 	err = fileutils.Touch(FileLicense)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileReport)
 	err = fileutils.Touch(FileReport)
 	err = fileutils.Touch(FileReport)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileName)
 	err = fileutils.Touch(FileName)
 	err = fileutils.Touch(FileName)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileEnvPrefix)
 	err = fileutils.Touch(FileEnvPrefix)
 	err = fileutils.Touch(FileEnvPrefix)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileSystemYaml)
+	err = fileutils.Touch(FileSystemYaml)
+	if err != nil {
+		return err
+	}
+
+	log.Printf("generate: touch file %s\n", FileBuildDateTxt)
 	err = fileutils.Touch(FileBuildDateTxt)
 	err = fileutils.Touch(FileBuildDateTxt)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileCommitDateTxt)
 	err = fileutils.Touch(FileCommitDateTxt)
 	err = fileutils.Touch(FileCommitDateTxt)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileTagDataTxt)
 	err = fileutils.Touch(FileTagDataTxt)
 	err = fileutils.Touch(FileTagDataTxt)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileTagCommitData)
 	err = fileutils.Touch(FileTagCommitData)
 	err = fileutils.Touch(FileTagCommitData)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileRandomData)
 	err = fileutils.Touch(FileRandomData)
 	err = fileutils.Touch(FileRandomData)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: touch file %s\n", FileReleaseInfoMD)
 	err = fileutils.Touch(FileReleaseInfoMD)
 	err = fileutils.Touch(FileReleaseInfoMD)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 8 - 1
tool/generate/builddate/build_date_data.go

@@ -8,11 +8,18 @@ import (
 	"fmt"
 	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
+	"log"
 	"time"
 	"time"
 )
 )
 
 
 var buildTime = time.Now()
 var buildTime = time.Now()
 
 
 func WriteBuildDateData() error {
 func WriteBuildDateData() error {
-	return fileutils.Write(basefile.FileBuildDateTxt, fmt.Sprint(buildTime.Unix()))
+	val := fmt.Sprint(buildTime.Unix())
+
+	log.Printf("generate: write build data: %s UTC (timestaamp: %s)\n", buildTime.UTC().Format(time.DateTime), val)
+	defer log.Println("generate: write build data finish")
+
+	log.Printf("generate: write %s to file %s\n", val, basefile.FileBuildDateTxt)
+	return fileutils.Write(basefile.FileBuildDateTxt, val)
 }
 }

+ 13 - 4
tool/generate/changelog/changelog_data.go

@@ -6,6 +6,7 @@ package changelog
 
 
 import (
 import (
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/cleanstringutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/cleanstringutils"
+	"log"
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
@@ -24,9 +25,13 @@ func GetLastChangLog() string {
 }
 }
 
 
 func getLastChangLog() string {
 func getLastChangLog() string {
+	log.Printf("generate: get %s data\n", FileChangelog)
+	defer log.Printf("generate: get %s data finish\n", FileChangelog)
+
 	dat, err := os.ReadFile(FileChangelog)
 	dat, err := os.ReadFile(FileChangelog)
 	if err != nil {
 	if err != nil {
-		panic(err)
+		log.Printf("generate: read file %s failed: %s\n", FileChangelog, err.Error())
+		return ""
 	}
 	}
 
 
 	logSrc := strings.Split(cleanstringutils.GetString(string(dat)), "\n")
 	logSrc := strings.Split(cleanstringutils.GetString(string(dat)), "\n")
@@ -36,29 +41,33 @@ func getLastChangLog() string {
 
 
 	// 定位最新版本
 	// 定位最新版本
 FindVersionCycle:
 FindVersionCycle:
-	for {
+	for ; ; index++ {
 		if index >= len(logSrc) {
 		if index >= len(logSrc) {
-			panic("Error CHANGELOG.md: can not find the log")
+			log.Printf("generate: read file %s failed: log title not found\n", FileChangelog)
+			return ""
 		}
 		}
 
 
 		s := logSrc[index]
 		s := logSrc[index]
 		if strings.HasPrefix(s, "## [") && !strings.HasPrefix(s, "## [未") {
 		if strings.HasPrefix(s, "## [") && !strings.HasPrefix(s, "## [未") {
+			log.Printf("generate: read file %s title [index: %d]: %s\n", FileChangelog, index, s)
 			res.WriteString(s + "\n")
 			res.WriteString(s + "\n")
 			break FindVersionCycle
 			break FindVersionCycle
 		}
 		}
 	}
 	}
 
 
 GetVersionLogCycle:
 GetVersionLogCycle:
-	for {
+	for index++; ; index++ { // 初始化的 index++ 是为了从标题哪一行向下走一行。因为对于上面的循环(FindVersionCycle)来说,break 后置语句(index++)也就不会执行,若本循环开头不执行(index++)则会导致本循环读取的第一条数据和 FindVersionCycle 循环读取的第一条数据为同一行(标题行)
 		if index >= len(logSrc) {
 		if index >= len(logSrc) {
 			break GetVersionLogCycle
 			break GetVersionLogCycle
 		}
 		}
 
 
 		s := logSrc[index]
 		s := logSrc[index]
 		if strings.HasPrefix(s, "## [") {
 		if strings.HasPrefix(s, "## [") {
+			log.Printf("generate: read file %s content end [index: %d]\n", FileChangelog, index)
 			break GetVersionLogCycle
 			break GetVersionLogCycle
 		}
 		}
 
 
+		log.Printf("generate: read file %s content [index: %d]: %s\n", FileChangelog, index, s)
 		res.WriteString(s + "\n")
 		res.WriteString(s + "\n")
 	}
 	}
 
 

+ 111 - 8
tool/generate/git/git_data.go

@@ -7,14 +7,16 @@ package git
 import (
 import (
 	"fmt"
 	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
+	"github.com/SongZihuan/BackendServerTemplate/tool/generate/mod"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/gitutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/gitutils"
-	"github.com/SongZihuan/BackendServerTemplate/tool/utils/modutils"
+	"log"
+	"os"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 )
 )
 
 
-var once sync.Once
+var onceGitInfo sync.Once
 var lastCommit string = ""
 var lastCommit string = ""
 var lastTag string = ""
 var lastTag string = ""
 var lastTagCommit string = ""
 var lastTagCommit string = ""
@@ -22,8 +24,11 @@ var secondToLastTag string = ""
 var secondToLastTagCommit string = ""
 var secondToLastTagCommit string = ""
 var firstCommit string = ""
 var firstCommit string = ""
 
 
+var onceIsGithub sync.Once
+var isGithub bool = false
+
 func InitGitData() (err error) {
 func InitGitData() (err error) {
-	once.Do(func() {
+	onceGitInfo.Do(func() {
 		err = initGitData()
 		err = initGitData()
 	})
 	})
 	return err
 	return err
@@ -31,9 +36,13 @@ func InitGitData() (err error) {
 
 
 func initGitData() (err error) {
 func initGitData() (err error) {
 	if !gitutils.HasGit() {
 	if !gitutils.HasGit() {
+		log.Println("generate: `.git` not found, get git info skip")
 		return nil
 		return nil
 	}
 	}
 
 
+	log.Println("generate: get git info")
+	defer log.Println("generate: get git info finish")
+
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
 			lastCommit = ""
 			lastCommit = ""
@@ -49,36 +58,52 @@ func initGitData() (err error) {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	log.Printf("generate: get git last commit: %s\n", lastCommit)
 
 
 	firstCommit, err = gitutils.GetFirstCommit()
 	firstCommit, err = gitutils.GetFirstCommit()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	log.Printf("generate: get git first commit: %s\n", firstCommit)
 
 
 	tagList, err := gitutils.GetTagListWithFilter(func(s string) bool {
 	tagList, err := gitutils.GetTagListWithFilter(func(s string) bool {
 		return strings.HasPrefix(s, "v")
 		return strings.HasPrefix(s, "v")
 	})
 	})
-	if err == nil {
+	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: get git tag list length: %d\n", len(tagList))
+
 	if len(tagList) > 0 {
 	if len(tagList) > 0 {
 		lastTag = tagList[0]
 		lastTag = tagList[0]
+		log.Printf("generate: get git last tag: %s\n", lastTag)
+
 		lastTagCommit, err = gitutils.GetTagCommit(lastTag)
 		lastTagCommit, err = gitutils.GetTagCommit(lastTag)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		log.Printf("generate: get git last tag commist: %s\n", lastTagCommit)
+	} else {
+		lastTag = ""
+		lastTagCommit = ""
+		log.Println("generate: skip to get git last tag and last tag commit")
 	}
 	}
 
 
 	if len(tagList) > 1 {
 	if len(tagList) > 1 {
 		secondToLastTag = tagList[1]
 		secondToLastTag = tagList[1]
+		log.Printf("generate: get git second to last tag: %s\n", secondToLastTag)
+
 		secondToLastTagCommit, err = gitutils.GetTagCommit(secondToLastTag)
 		secondToLastTagCommit, err = gitutils.GetTagCommit(secondToLastTag)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		log.Printf("generate: get git second to last tag commit: %s\n", secondToLastTagCommit)
 	} else {
 	} else {
 		secondToLastTag = ""
 		secondToLastTag = ""
 		secondToLastTagCommit = ""
 		secondToLastTagCommit = ""
+		log.Println("generate: skip to get git second to last tag and second to last tag commit")
+
 	}
 	}
 
 
 	return nil
 	return nil
@@ -90,22 +115,29 @@ func Version() string {
 }
 }
 
 
 func WriteGitData() (err error) {
 func WriteGitData() (err error) {
+	log.Println("generate: write git data")
+	defer log.Println("generate: write git data finish")
+
 	_ = InitGitData()
 	_ = InitGitData()
 
 
+	log.Printf("generate: write %s to file %s\n", lastCommit, basefile.FileCommitDateTxt)
 	err = fileutils.Write(basefile.FileCommitDateTxt, lastCommit)
 	err = fileutils.Write(basefile.FileCommitDateTxt, lastCommit)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: write %s to file %s\n", lastTag, basefile.FileTagDataTxt)
 	err = fileutils.Write(basefile.FileTagDataTxt, lastTag)
 	err = fileutils.Write(basefile.FileTagDataTxt, lastTag)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	log.Printf("generate: write %s to file %s\n", lastTagCommit, basefile.FileTagCommitData)
 	err = fileutils.Write(basefile.FileTagCommitData, lastTagCommit)
 	err = fileutils.Write(basefile.FileTagCommitData, lastTagCommit)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+
 	return nil
 	return nil
 }
 }
 
 
@@ -117,20 +149,91 @@ func GetGitHubCompareMD() string {
 		return ""
 		return ""
 	}
 	}
 
 
-	return fmt.Sprintf("**Git Changelog:[%s](%s)", compare, url)
+	return fmt.Sprintf("**Git Changelog:** [%s](%s)", compare, url)
 }
 }
 
 
 func GetGitHubCompareURL() (string, string) {
 func GetGitHubCompareURL() (string, string) {
 	_ = InitGitData()
 	_ = InitGitData()
 
 
-	if !modutils.IsGitHub || lastTag == "" || firstCommit == lastTagCommit {
+	if !IsGitHub() || lastTag == "" || firstCommit == lastTagCommit {
+		return "", ""
+	}
+
+	moduleName, err := mod.GetGoModuleName()
+	if err != nil {
 		return "", ""
 		return "", ""
 	}
 	}
 
 
 	if secondToLastTag != "" {
 	if secondToLastTag != "" {
 		compare := fmt.Sprintf("%s...%s", secondToLastTag, lastTag)
 		compare := fmt.Sprintf("%s...%s", secondToLastTag, lastTag)
-		return compare, fmt.Sprintf("https://%s/compare/%s", modutils.ModPath, compare)
+		return compare, fmt.Sprintf("https://%s/compare/%s", moduleName, compare)
+	}
+
+	return lastTag, fmt.Sprintf("https://%s/compare/%s...%s", moduleName, firstCommit, lastTag)
+}
+
+func IsGitHub() bool {
+	onceIsGithub.Do(func() {
+		moduleName, err := mod.GetGoModuleName()
+		if err != nil {
+			log.Println("generate: the module is not on github, because module name not found")
+			isGithub = false
+			return
+		}
+
+		if strings.HasPrefix(moduleName, "github.com/") {
+			log.Println("generate: the module is on github")
+			isGithub = true
+		} else {
+			log.Println("generate: the module is not on github")
+			isGithub = false
+		}
+	})
+	return isGithub
+}
+
+func WriteGitIgnore() error {
+	if !gitutils.HasGit() {
+		log.Printf("generate: `.git` not found, write %s skip\n", basefile.FileGitIgnore)
+		return nil
+	}
+
+	log.Printf("generate: write %s file\n", basefile.FileGitIgnore)
+	defer log.Printf("generate: write %s file finish\n", basefile.FileGitIgnore)
+
+	s, err := os.Stat(basefile.FileGitIgnore)
+	if err != nil {
+		log.Printf("generaate: file %s not exists, create new one\n", basefile.FileGitIgnore)
+		return newGitIgnore()
+	}
+
+	if s.IsDir() {
+		log.Printf("generaate: %s is dir\n", basefile.FileGitIgnore)
+		return fmt.Errorf("%s is dir", basefile.FileGitIgnore)
 	}
 	}
 
 
-	return lastTag, fmt.Sprintf("https://%s/compare/%s...%s", modutils.ModPath, firstCommit, lastTag)
+	res, err := fileutils.CheckFileByLine(basefile.FileGitIgnore, func(s string) bool {
+		if s == basefile.GitIgnoreExtFlag {
+			return true
+		}
+		return false
+	})
+	if err != nil {
+		return err
+	} else if res {
+		log.Printf("generaate: file %s check ok\n", basefile.FileGitIgnore)
+		return nil
+	}
+
+	log.Printf("generaate: auto ignore '%s', write to file %s\n", basefile.GitIgnoreExtFlag, basefile.FileGitIgnore)
+	return appendGitIgnore()
+}
+
+func newGitIgnore() error {
+	return fileutils.Write(basefile.FileGitIgnore, fmt.Sprintf("# auto write by go generate\n%s\n", basefile.GitIgnoreExtFlag))
+}
+
+func appendGitIgnore() error {
+	// 写入前添加\n,确保在新的一行
+	return fileutils.AppendOnExistsFile(basefile.FileGitIgnore, fmt.Sprintf("\n# auto write by go generate\n%s\n", basefile.GitIgnoreExtFlag))
 }
 }

+ 15 - 1
tool/generate/main.go

@@ -8,8 +8,10 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/builddate"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/builddate"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/git"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/git"
+	"github.com/SongZihuan/BackendServerTemplate/tool/generate/mod"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/random"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/random"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/releaseinfo"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/releaseinfo"
+	"log"
 	"os"
 	"os"
 )
 )
 
 
@@ -20,7 +22,14 @@ func main() {
 func command() int {
 func command() int {
 	var err error
 	var err error
 
 
-	err = basefile.CreateBaseFile()
+	log.Println("generate start to run")
+
+	_, err = mod.GetGoModuleName() // 提前一步帕胺的
+	if err != nil {
+		return ReturnError(err)
+	}
+
+	err = basefile.TouchBaseFile()
 	if err != nil {
 	if err != nil {
 		return ReturnError(err)
 		return ReturnError(err)
 	}
 	}
@@ -40,6 +49,11 @@ func command() int {
 		return ReturnError(err)
 		return ReturnError(err)
 	}
 	}
 
 
+	err = git.WriteGitIgnore()
+	if err != nil {
+		return ReturnError(err)
+	}
+
 	err = random.WriteRandomData()
 	err = random.WriteRandomData()
 	if err != nil {
 	if err != nil {
 		return ReturnError(err)
 		return ReturnError(err)

+ 66 - 0
tool/generate/mod/mod.go

@@ -0,0 +1,66 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package mod
+
+import (
+	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/tool/utils/cleanstringutils"
+	"log"
+	"os"
+	"regexp"
+	"strings"
+	"sync"
+)
+
+const FileGoMod = "./go.mod"
+const module = "module"
+
+var validModuleNameRegex = regexp.MustCompile(`^[a-zA-Z0-9]+([./-]?[a-zA-Z0-9]+)*$`)
+
+var once sync.Once
+var goModuleName string = ""
+
+func GetGoModuleName() (string, error) {
+	var err error
+
+	once.Do(func() {
+		goModuleName, err = getGoModuleName()
+	})
+	if goModuleName == "" && err == nil {
+		err = fmt.Errorf("go module name not found")
+	}
+
+	return goModuleName, err
+}
+
+func getGoModuleName() (string, error) {
+	log.Println("generate: find the go mod name")
+	defer log.Println("generate: find the go mod name finish")
+
+	dat, err := os.ReadFile(FileGoMod)
+	if err != nil {
+		return "", err
+	}
+
+	goMod := strings.TrimPrefix(cleanstringutils.GetString(string(dat)), "\n")
+
+	moduleLine := strings.TrimSpace(strings.Split(goMod, "\n")[0])
+
+	if !strings.Contains(moduleLine, module) && len(moduleLine) > len(module) {
+		return "", fmt.Errorf("go.mod error: %s not found", module)
+	}
+
+	moduleName := cleanstringutils.GetStringOneLine(moduleLine[len(module):])
+	if !IsValidGoModuleName(moduleName) {
+		return "", fmt.Errorf("go.mod error: '%s' is not a valid go module name", moduleName)
+	}
+
+	log.Printf("generate: go mod name get: %s\n", moduleName)
+	return moduleName, nil
+}
+
+func IsValidGoModuleName(name string) bool {
+	return validModuleNameRegex.MatchString(name)
+}

+ 8 - 1
tool/generate/random/random_data.go

@@ -8,8 +8,15 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/randomutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/randomutils"
+	"log"
 )
 )
 
 
 func WriteRandomData() error {
 func WriteRandomData() error {
-	return fileutils.Write(basefile.FileRandomData, randomutils.GenerateRandomString(40))
+	log.Println("generate: write random number (length=40) data")
+	defer log.Println("generate: write random number (length=40) data finish")
+
+	val := randomutils.GenerateRandomString(40)
+
+	log.Printf("generate: write %s to file %s\n", val, basefile.FileRandomData)
+	return fileutils.Write(basefile.FileRandomData, val)
 }
 }

+ 18 - 0
tool/generate/releaseinfo/release_data.go

@@ -9,6 +9,7 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/changelog"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/changelog"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/git"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/git"
+	"log"
 	"os"
 	"os"
 	"text/template"
 	"text/template"
 )
 )
@@ -32,6 +33,9 @@ func init() {
 }
 }
 
 
 func WriteReleaseData() error {
 func WriteReleaseData() error {
+	log.Println("generate: write release info data data")
+	defer log.Println("generate: write write release info data finish")
+
 	file, err := os.OpenFile(basefile.FileReleaseInfoMD, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
 	file, err := os.OpenFile(basefile.FileReleaseInfoMD, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -40,6 +44,20 @@ func WriteReleaseData() error {
 		_ = file.Close()
 		_ = file.Close()
 	}()
 	}()
 
 
+	v := git.Version()
+
+	cl := changelog.GetLastChangLog()
+
+	gcl := git.GetGitHubCompareMD()
+
+	log.Printf("generate: release info version: %s\n", v)
+	if gcl != "" {
+		log.Printf("generate: release info github changelog: %s\n", gcl)
+	} else {
+		log.Println("generate: release info github changelog: without")
+	}
+	log.Printf("generate: release info changelog length=%d\n", len(cl))
+
 	return releaseTemplate.Execute(file, templateData{
 	return releaseTemplate.Execute(file, templateData{
 		Version:       git.Version(),
 		Version:       git.Version(),
 		ChangeLog:     changelog.GetLastChangLog(),
 		ChangeLog:     changelog.GetLastChangLog(),

+ 2 - 2
tool/generate/return.go

@@ -10,11 +10,11 @@ const exitCodeSuccess = 0
 const exitCodeFailed = 1
 const exitCodeFailed = 1
 
 
 func ReturnError(err error) int {
 func ReturnError(err error) int {
-	log.Printf("Error: %s\n", err.Error())
+	log.Printf("generate: error: %s\n", err.Error())
 	return exitCodeFailed
 	return exitCodeFailed
 }
 }
 
 
 func ReturnSuccess() int {
 func ReturnSuccess() int {
-	log.Println("Success!")
+	log.Println("generate: success!")
 	return exitCodeSuccess
 	return exitCodeSuccess
 }
 }

+ 1 - 1
tool/utils/cleanstringutils/moreline.go

@@ -8,7 +8,7 @@ import "strings"
 
 
 func GetString(data string) (res string) {
 func GetString(data string) (res string) {
 	res = strings.Replace(data, "\r", "", -1)
 	res = strings.Replace(data, "\r", "", -1)
-	res = strings.Split(res, "\n")[0]
+	res = strings.TrimRight(res, "\n")
 	res = strings.TrimSpace(res)
 	res = strings.TrimSpace(res)
 	return res
 	return res
 }
 }

+ 36 - 1
tool/utils/fileutils/write.go

@@ -4,7 +4,11 @@
 
 
 package fileutils
 package fileutils
 
 
-import "os"
+import (
+	"github.com/SongZihuan/BackendServerTemplate/tool/utils/cleanstringutils"
+	"os"
+	"strings"
+)
 
 
 func Write(filePath string, dat string) error {
 func Write(filePath string, dat string) error {
 	// 尝试打开文件
 	// 尝试打开文件
@@ -18,3 +22,34 @@ func Write(filePath string, dat string) error {
 	_, err = file.Write([]byte(dat))
 	_, err = file.Write([]byte(dat))
 	return err
 	return err
 }
 }
+
+func AppendOnExistsFile(filePath string, dat string) error {
+	// 尝试打开文件(若文件不存在则返回错误)
+	file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+	_, err = file.Write([]byte(dat))
+	return err
+}
+
+// CheckFileByLine 检查文件每一行,若fn返回 true 则本函数返回 true,否则返回false。
+// 传入 fn 的字符串不以 \n 结尾,空字符串也会传入
+func CheckFileByLine(filePath string, fn func(string) bool) (bool, error) {
+	dat, err := os.ReadFile(filePath)
+	if err != nil {
+		return false, err
+	}
+
+	fileLine := strings.Split(cleanstringutils.GetString(string(dat)), "\n")
+	for _, l := range fileLine {
+		if fn(l) {
+			return true, nil
+		}
+	}
+
+	return false, nil
+}

+ 2 - 2
tool/utils/gitutils/git.go

@@ -27,7 +27,7 @@ func GetLastCommit() (string, error) {
 }
 }
 
 
 func GetTagListWithFilter(filter func(string) bool) ([]string, error) {
 func GetTagListWithFilter(filter func(string) bool) ([]string, error) {
-	ret, err := executils.RunOnline("git", "for-each-ref", "--sort=-creatordate", "--format", "%(refname:short)", "refs/tags/")
+	ret, err := executils.Run("git", "for-each-ref", "--sort=-creatordate", "--format", "%(refname:short)", "refs/tags/")
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -36,7 +36,7 @@ func GetTagListWithFilter(filter func(string) bool) ([]string, error) {
 	tagListSrc := strings.Split(ret, "\n")
 	tagListSrc := strings.Split(ret, "\n")
 	tagList := make([]string, 0, len(tagListSrc))
 	tagList := make([]string, 0, len(tagListSrc))
 
 
-	for _, tag := range tagList {
+	for _, tag := range tagListSrc {
 		tag = strings.TrimSpace(tag)
 		tag = strings.TrimSpace(tag)
 		if tag == "" || (filter != nil && !filter(tag)) {
 		if tag == "" || (filter != nil && !filter(tag)) {
 			continue
 			continue

+ 0 - 23
tool/utils/modutils/mod.go

@@ -1,23 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package modutils
-
-import (
-	"runtime/debug"
-	"strings"
-)
-
-var ModPath = ""
-var IsGitHub bool = false
-
-func init() {
-	info, ok := debug.ReadBuildInfo()
-	if !ok {
-		panic("read build info failed")
-	}
-
-	ModPath = info.Main.Path
-	IsGitHub = strings.HasPrefix(ModPath, "github.com/")
-}