package giq import ( "fmt" "io" "math/rand" "os" "path" "path/filepath" "strings" gogit "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) func (g *Gogit) Whoami() string { return "I am Gogit!" } func detectGitPath(path string) (string, error) { path, err := filepath.Abs(path) if err != nil { return "", err } for { fi, err := os.Stat(filepath.Join(path, ".git")) if err == nil { if !fi.IsDir() { return "", fmt.Errorf(".git exist but is not a directory") } return filepath.Join(path, ".git"), nil } if !os.IsNotExist(err) { return "", err } ok, err := isGitDir(path) if err != nil { return "", err } if ok { return path, nil } if parent := filepath.Dir(path); parent == path { return "", fmt.Errorf(".git not found") } else { path = parent } } } func isGitDir(path string) (bool, error) { markers := []string{"HEAD", "objects", "refs"} for _, marker := range markers { _, err := os.Stat(filepath.Join(path, marker)) if err == nil { continue } if !os.IsNotExist(err) { return false, err } else { return false, nil } } return true, nil } func isPublish(r gogit.Repository, prevCommit, lastCommit string) bool { ret := false pCommit, err := r.ResolveRevision(plumbing.Revision(prevCommit)) check(err) lCommit, err := r.ResolveRevision(plumbing.Revision(lastCommit)) check(err) // fileName := "README.md" hashCommitRange, err := r.Log(&gogit.LogOptions{ From: *lCommit, // FileName: &fileName, // Order: }) check(err) hashCommitMap := make(map[string]bool) err = hashCommitRange.ForEach(func(c *object.Commit) error { // fmt.Println(c.Hash.String(), c.Message) hashCommitMap[c.Hash.String()] = true ok := strings.Contains(c.Message, "!publish!") if ok { ret = true return io.EOF } else if c.Hash == *pCommit { // return storer.ErrStop return io.EOF } return nil }) if ret { return true } fileName := "PUBLISH_TRIGGER.md" fileNameCommitRange, err := r.Log(&gogit.LogOptions{ FileName: &fileName, }) check(err) err = fileNameCommitRange.ForEach(func(c *object.Commit) error { _, ok := hashCommitMap[c.Hash.String()] if ok { // return storer.ErrStop ret = true return io.EOF } return nil }) // fmt.Println(hashCommitMap) if ret { return true } return false } func (g *Gogit) AddBareWorktree(gitRepoPath, gitIndexPath, gitWorktree, gexe string) { tmpRepoPath := filepath.Join(os.TempDir(), gitWorktree) _, err := gogit.PlainClone(tmpRepoPath, false, &gogit.CloneOptions{ URL: gitRepoPath, Depth: 1, Tags: gogit.NoTags, // NoCheckout: true, }) check(err) // fmt.Println("WORKTREE:", tmpRepoPath) } func (g *Gogit) RemoveBareWorktree(gitRepoPath, gitIndexPath, gitWorktree, gexe string) { tmpRepoPath := filepath.Join(os.TempDir(), gitWorktree) err := os.RemoveAll(tmpRepoPath) check(err) } func (g *Gogit) GitStruct(hookPath, hookContext, hookStdinput, gexe string) Git { var git Git _ = gexe gitBase, err := detectGitPath(hookPath) check(err) repoPath := gitBase git.IsBare = true base := path.Base(gitBase) if base == ".git" { git.IsBare = false repoPath = strings.Replace(gitBase, ".git", "", 1) } r, err := gogit.PlainOpen(repoPath) check(err) gitPreviousCommit, err := r.ResolveRevision(plumbing.Revision("HEAD^")) check(err) headCommit, err := r.Head() check(err) prevCommit := gitPreviousCommit.String() lastCommit := headCommit.Hash().String() if hookContext == "PostReceive" { revs := strings.Fields(hookStdinput) prevCommit = revs[0] lastCommit = revs[1] } git.Publish = isPublish(*r, prevCommit, lastCommit) git.RepoPath = repoPath git.PreviousCommit = prevCommit git.LastCommit = lastCommit git.Branch = headCommit.Name().Short() git.IndexPath = filepath.Join("/", ".git", "index") if git.IsBare { git.IndexPath = filepath.Join("/", "index") } git.Worktree = fmt.Sprintf("sandpoints_repo_%06d", rand.Intn(100001)) git.TmpRepoPath = filepath.Join(os.TempDir(), git.Worktree) return git }