Selaa lähdekoodia

新增生成补丁工具及相关功能

添加了生成补丁的完整功能,包括获取Git信息、创建补丁文件等核心逻辑,同时优化了文件操作和忽略规则处理,提升了代码的可维护性和扩展性。
SongZihuan 1 päivä sitten
vanhempi
sitoutus
4f13f9e025

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

@@ -117,6 +117,9 @@ jobs:
       - name: Copy Release Info
         run: cp "${{ github.workspace }}/release_info.md.ignore" "${{ github.workspace }}/output/release_info.md"
 
+      - name: Copy Patch File
+        run: cp "${{ github.workspace }}/update.patch.ignore" "${{ github.workspace }}/output/update.patch"
+
       - name: List build directory
         run: |
           ls -l "${{ github.workspace }}/output"
@@ -234,7 +237,7 @@ jobs:
         id: create_release
         uses: ncipollo/release-action@v1
         with:
-          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/update.patch,${{ 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
           allowUpdates: false
           bodyFile: "${{ github.workspace }}/output/release_info.md"

+ 7 - 11
tool/generate/basefile/basefile.go

@@ -5,15 +5,11 @@
 package basefile
 
 import (
+	"github.com/SongZihuan/BackendServerTemplate/tool/global"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"log"
 )
 
-const (
-	FileIgnoreExt    = ".ignore"
-	GitIgnoreExtFlag = "*" + FileIgnoreExt
-)
-
 const (
 	FileVersion    = "./VERSION"
 	FileLicense    = "./LICENSE"
@@ -22,13 +18,13 @@ const (
 	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
+	FileBuildDateTxt  = "./build_date.dat" + global.FileIgnoreExt
+	FileCommitDateTxt = "./commit_data.dat" + global.FileIgnoreExt
+	FileTagDataTxt    = "./tag_data.dat" + global.FileIgnoreExt
+	FileTagCommitData = "./tag_commit_data.dat" + global.FileIgnoreExt
+	FileRandomData    = "./random_data.dat" + global.FileIgnoreExt
 
-	FileReleaseInfoMD = "./release_info.md" + FileIgnoreExt
+	FileReleaseInfoMD = "./release_info.md" + global.FileIgnoreExt
 
 	FileGitIgnore = "./.gitignore"
 )

+ 5 - 4
tool/generate/git/git_data.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/basefile"
 	"github.com/SongZihuan/BackendServerTemplate/tool/generate/mod"
+	"github.com/SongZihuan/BackendServerTemplate/tool/global"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/gitutils"
 	"log"
@@ -212,7 +213,7 @@ func WriteGitIgnore() error {
 	}
 
 	res, err := fileutils.CheckFileByLine(basefile.FileGitIgnore, func(s string) bool {
-		if s == basefile.GitIgnoreExtFlag {
+		if s == global.GitIgnoreExtFlag {
 			return true
 		}
 		return false
@@ -224,15 +225,15 @@ func WriteGitIgnore() error {
 		return nil
 	}
 
-	log.Printf("generaate: auto ignore '%s', write to file %s\n", basefile.GitIgnoreExtFlag, basefile.FileGitIgnore)
+	log.Printf("generaate: auto ignore '%s', write to file %s\n", global.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))
+	return fileutils.Write(basefile.FileGitIgnore, fmt.Sprintf("# auto write by go generate\n%s\n", global.GitIgnoreExtFlag))
 }
 
 func appendGitIgnore() error {
 	// 写入前添加\n,确保在新的一行
-	return fileutils.AppendOnExistsFile(basefile.FileGitIgnore, fmt.Sprintf("\n# auto write by go generate\n%s\n", basefile.GitIgnoreExtFlag))
+	return fileutils.AppendOnExistsFile(basefile.FileGitIgnore, fmt.Sprintf("\n# auto write by go generate\n%s\n", global.GitIgnoreExtFlag))
 }

+ 10 - 0
tool/global/varibale.go

@@ -0,0 +1,10 @@
+// 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 global
+
+const (
+	FileIgnoreExt    = ".ignore"
+	GitIgnoreExtFlag = "*" + FileIgnoreExt
+)

+ 140 - 0
tool/patch/git.go

@@ -0,0 +1,140 @@
+// 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 main
+
+import (
+	"github.com/SongZihuan/BackendServerTemplate/tool/global"
+	"github.com/SongZihuan/BackendServerTemplate/tool/utils/fileutils"
+	"github.com/SongZihuan/BackendServerTemplate/tool/utils/gitutils"
+	"log"
+	"strings"
+	"sync"
+)
+
+const filePatchFile = "update.patch" + global.FileIgnoreExt
+
+var onceGitInfo sync.Once
+var toCommit string = ""
+var fromCommit string = ""
+
+var excludes = []string{
+	// 配置文件
+	"VERSION",
+	"REPORT",
+	"NAME",
+	"LICENSE",
+	"ENV_PREFIX",
+	// 服务配置文件
+	"SERVICE.yaml",
+	// 文档
+	"SECURITY.md",
+	"README.md",
+	"CONTRIBUTORS.md",
+	"CONTRIBUTING.md",
+	"CODE_OF_CONDUCT.md",
+	"CHANGELOG_SPECIFICATION.md",
+	"CHANGELOG.md",
+	"dev-git-hooks/",
+}
+
+func InitGitData() (err error) {
+	onceGitInfo.Do(func() {
+		err = initGitData()
+	})
+	return err
+}
+
+func initGitData() (err error) {
+	if !gitutils.HasGit() {
+		log.Println("generate patch: `.git` not found, get git info skip")
+		return nil
+	}
+
+	log.Println("generate patch: get git info")
+	defer log.Println("generate patch: get git info finish")
+
+	defer func() {
+		if err != nil {
+			toCommit = ""
+			fromCommit = ""
+		}
+	}()
+
+	tagList, err := gitutils.GetTagListWithFilter(func(s string) bool {
+		return strings.HasPrefix(s, "v")
+	})
+	if err != nil {
+		return err
+	}
+	log.Printf("generate patch: get git tag list length: %d\n", len(tagList))
+
+	if len(tagList) == 0 {
+		toCommit, err = gitutils.GetLastCommit()
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git to commit: %s\n", toCommit)
+
+		fromCommit, err = gitutils.GetFirstCommit()
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git from commit: %s\n", fromCommit)
+	} else if len(tagList) == 1 {
+		toCommit, err = gitutils.GetTagCommit(tagList[0])
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git to commist (from tag '%s') : %s\n", tagList[0], toCommit)
+
+		fromCommit, err = gitutils.GetFirstCommit()
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git from commit: %s\n", fromCommit)
+	} else if len(tagList) >= 2 {
+		toCommit, err = gitutils.GetTagCommit(tagList[0])
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git to commist (from tag '%s') : %s\n", tagList[0], toCommit)
+
+		fromCommit, err = gitutils.GetTagCommit(tagList[1])
+		if err != nil {
+			return err
+		}
+		log.Printf("generate patch: get git from commist (from tag '%s') : %s\n", tagList[1], toCommit)
+	} else {
+		panic("unreachable")
+	}
+
+	return nil
+}
+
+func CreatePatch() error {
+	err := InitGitData()
+	if err != nil {
+		return err
+	}
+
+	if !gitutils.HasGit() {
+		return nil
+	}
+
+	log.Println("generate patch: create patch file")
+	defer log.Println("generate patch: create patch file")
+
+	if fromCommit == toCommit {
+		log.Println("generate patch: only one commit, skip to create patch file")
+		return fileutils.WriteEmpty(filePatchFile)
+	}
+
+	res, err := gitutils.GetPatch(fromCommit, toCommit, excludes...)
+	if err != nil {
+		return err
+	}
+
+	return fileutils.WriteBytes(filePatchFile, res)
+}

+ 27 - 0
tool/patch/main.go

@@ -0,0 +1,27 @@
+// 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 main
+
+import "os"
+
+func main() {
+	os.Exit(command())
+}
+
+func command() int {
+	var err error
+
+	err = InitGitData()
+	if err != nil {
+		return ReturnError(err)
+	}
+
+	err = CreatePatch()
+	if err != nil {
+		return ReturnError(err)
+	}
+
+	return ReturnSuccess()
+}

+ 20 - 0
tool/patch/return.go

@@ -0,0 +1,20 @@
+// 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 main
+
+import "log"
+
+const exitCodeSuccess = 0
+const exitCodeFailed = 1
+
+func ReturnError(err error) int {
+	log.Printf("generate: error: %s\n", err.Error())
+	return exitCodeFailed
+}
+
+func ReturnSuccess() int {
+	log.Println("generate: success!")
+	return exitCodeSuccess
+}

+ 15 - 0
tool/utils/executils/exec.go

@@ -34,3 +34,18 @@ func RunOnline(name string, args ...string) (string, error) {
 
 	return cleanstringutils.GetStringOneLine(res), nil
 }
+
+func RunBytes(name string, args ...string) ([]byte, error) {
+	cmd := exec.Command(name, args...)
+
+	var out bytes.Buffer
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = &out
+	cmd.Stderr = os.Stderr
+
+	if err := cmd.Run(); err != nil {
+		return nil, err
+	}
+
+	return out.Bytes(), nil
+}

+ 25 - 0
tool/utils/fileutils/write.go

@@ -23,6 +23,31 @@ func Write(filePath string, dat string) error {
 	return err
 }
 
+func WriteBytes(filePath string, dat []byte) error {
+	// 尝试打开文件
+	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+	_, err = file.Write(dat)
+	return err
+}
+
+func WriteEmpty(filePath string) error {
+	// 尝试打开文件
+	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+	return err
+}
+
 func AppendOnExistsFile(filePath string, dat string) error {
 	// 尝试打开文件(若文件不存在则返回错误)
 	file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)

+ 11 - 0
tool/utils/gitutils/git.go

@@ -5,6 +5,7 @@
 package gitutils
 
 import (
+	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/cleanstringutils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/executils"
 	"github.com/SongZihuan/BackendServerTemplate/tool/utils/filesystemutils"
@@ -60,3 +61,13 @@ func GetTagCommit(tag string) (string, error) {
 func GetFirstCommit() (string, error) {
 	return executils.RunOnline("git", "rev-list", "--max-parents=0", "HEAD")
 }
+
+func GetPatch(from string, to string, excludes ...string) ([]byte, error) {
+	args := make([]string, 0, len(excludes)+3)
+	args = append(args, "diff", from, to, ".")
+	for _, e := range excludes {
+		args = append(args, fmt.Sprintf(":(exclude)%s", e))
+	}
+
+	return executils.RunBytes("git", args...)
+}