mirror of
https://github.com/beego/bee.git
synced 2024-12-18 13:40:49 +00:00
225 lines
5.4 KiB
Go
225 lines
5.4 KiB
Go
package git
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/beego/bee/internal/pkg/command"
|
|
"github.com/beego/bee/internal/pkg/utils"
|
|
beeLogger "github.com/beego/bee/logger"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// git tag
|
|
func GetTags(repoPath string, limit int) ([]string, error) {
|
|
repo, err := OpenRepository(repoPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = repo.Pull()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
list, err := repo.GetTags()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(list) > limit {
|
|
list = list[0:limit]
|
|
}
|
|
return list, nil
|
|
}
|
|
|
|
// clone repo
|
|
func CloneRepo(url string, dst string) (err error) {
|
|
if utils.IsExist(dst) {
|
|
return errors.New("dst is not empty, dst is " + dst)
|
|
}
|
|
if !utils.Mkdir(dst) {
|
|
err = errors.New("make dir error, dst is " + dst)
|
|
return
|
|
}
|
|
|
|
beeLogger.Log.Info("start git clone from " + url + ", to dst at " + dst)
|
|
_, stderr, err := command.ExecCmd("git", "clone", url, dst)
|
|
|
|
if err != nil {
|
|
beeLogger.Log.Error("error git clone from " + url + ", to dst at " + dst)
|
|
return concatenateError(err, stderr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CloneORPullRepo
|
|
func CloneORPullRepo(url string, dst string) error {
|
|
if !utils.IsDir(dst) {
|
|
return CloneRepo(url, dst)
|
|
} else {
|
|
utils.Mkdir(dst)
|
|
|
|
repo, err := OpenRepository(dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return repo.Pull()
|
|
}
|
|
}
|
|
|
|
//
|
|
func CloneRepoBranch(branch string, url string, dst string) error {
|
|
_, stderr, err := command.ExecCmd("git", "clone", "-b", branch, url, dst)
|
|
if err != nil {
|
|
return concatenateError(err, stderr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SortTag ...
|
|
type SortTag struct {
|
|
data []string
|
|
}
|
|
|
|
// Len ...
|
|
func (t *SortTag) Len() int {
|
|
return len(t.data)
|
|
}
|
|
|
|
// Swap ...
|
|
func (t *SortTag) Swap(i, j int) {
|
|
t.data[i], t.data[j] = t.data[j], t.data[i]
|
|
}
|
|
|
|
// Less ...
|
|
func (t *SortTag) Less(i, j int) bool {
|
|
return command.VerCompare(t.data[i], t.data[j]) == 1
|
|
}
|
|
|
|
// Sort ...
|
|
func (t *SortTag) Sort() []string {
|
|
sort.Sort(t)
|
|
return t.data
|
|
}
|
|
|
|
// Repository ...
|
|
type Repository struct {
|
|
Path string
|
|
}
|
|
|
|
// OpenRepository ...
|
|
func OpenRepository(repoPath string) (*Repository, error) {
|
|
repoPath, err := filepath.Abs(repoPath)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !utils.IsDir(repoPath) {
|
|
return nil, errors.New("no such file or directory")
|
|
}
|
|
|
|
return &Repository{Path: repoPath}, nil
|
|
}
|
|
|
|
// 拉取代码
|
|
func (repo *Repository) Pull() error {
|
|
beeLogger.Log.Info("git pull " + repo.Path)
|
|
_, stderr, err := command.ExecCmdDir(repo.Path, "git", "pull")
|
|
if err != nil {
|
|
return concatenateError(err, stderr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 获取tag列表
|
|
func (repo *Repository) GetTags() ([]string, error) {
|
|
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "tag", "-l")
|
|
if err != nil {
|
|
return nil, concatenateError(err, stderr)
|
|
}
|
|
tags := strings.Split(stdout, "\n")
|
|
tags = tags[:len(tags)-1]
|
|
|
|
so := &SortTag{data: tags}
|
|
return so.Sort(), nil
|
|
}
|
|
|
|
// 获取两个版本之间的修改日志
|
|
func (repo *Repository) GetChangeLogs(startVer, endVer string) ([]string, error) {
|
|
// git log --pretty=format:"%cd %cn: %s" --date=iso v1.8.0...v1.9.0
|
|
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "log", "--pretty=format:%cd %cn: %s", "--date=iso", startVer+"..."+endVer)
|
|
if err != nil {
|
|
return nil, concatenateError(err, stderr)
|
|
}
|
|
|
|
logs := strings.Split(stdout, "\n")
|
|
return logs, nil
|
|
}
|
|
|
|
// 获取两个版本之间的差异文件列表
|
|
func (repo *Repository) GetChangeFiles(startVer, endVer string, onlyFile bool) ([]string, error) {
|
|
// git diff --name-status -b v1.8.0 v1.9.0
|
|
param := "--name-status"
|
|
if onlyFile {
|
|
param = "--name-only"
|
|
}
|
|
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "diff", param, "-b", startVer, endVer)
|
|
if err != nil {
|
|
return nil, concatenateError(err, stderr)
|
|
}
|
|
lines := strings.Split(stdout, "\n")
|
|
return lines[:len(lines)-1], nil
|
|
}
|
|
|
|
// 获取两个版本间的新增或修改的文件数量
|
|
func (repo *Repository) GetDiffFileCount(startVer, endVer string) (int, error) {
|
|
cmd := "git diff --name-status -b " + startVer + " " + endVer + " |grep -v ^D |wc -l"
|
|
stdout, stderr, err := command.ExecCmdDir(repo.Path, "/bin/bash", "-c", cmd)
|
|
if err != nil {
|
|
return 0, concatenateError(err, stderr)
|
|
}
|
|
count, _ := strconv.Atoi(strings.TrimSpace(stdout))
|
|
return count, nil
|
|
}
|
|
|
|
// 导出版本到tar包
|
|
func (repo *Repository) Export(startVer, endVer string, filename string) error {
|
|
// git archive --format=tar.gz $endVer $(git diff --name-status -b $beginVer $endVer |grep -v ^D |grep -v Upgrade/ |awk '{print $2}') -o $tmpFile
|
|
|
|
cmd := ""
|
|
if startVer == "" {
|
|
cmd = "git archive --format=tar " + endVer + " | gzip > " + filename
|
|
} else {
|
|
cmd = "git archive --format=tar " + endVer + " $(dgit diff --name-status -b " + startVer + " " + endVer + "|grep -v ^D |awk '{print $2}') | gzip > " + filename
|
|
}
|
|
|
|
_, stderr, err := command.ExecCmdDir(repo.Path, "/bin/bash", "-c", cmd)
|
|
|
|
if err != nil {
|
|
return concatenateError(err, stderr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func concatenateError(err error, stderr string) error {
|
|
if len(stderr) == 0 {
|
|
return err
|
|
}
|
|
return fmt.Errorf("%v: %s", err, stderr)
|
|
}
|
|
|
|
// getGitProjectName 获取项目名称
|
|
func getGitProjectName(url string) (name string, err error) {
|
|
if !strings.Contains(url, ".git") {
|
|
return "", errors.New("Project address does not contain .git")
|
|
}
|
|
fileSlice := strings.Split(url, "/")
|
|
projectName := fileSlice[len(fileSlice)-1]
|
|
if projectName == "" {
|
|
return "", errors.New("Project name does not exist")
|
|
}
|
|
|
|
nameSlice := strings.Split(projectName, ".git")
|
|
|
|
return nameSlice[0], nil
|
|
}
|