package git import ( "io/ioutil" "os" "strings" "time" "gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/object" "golang.org/x/crypto/ssh" gitssh "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" ) func Sync(repo string, clonePath string, privateKeyPath string) (r *git.Repository, err error) { auth, err := getAuth(privateKeyPath) if err != nil { return } exists, err := dirExists(clonePath) if err != nil { return } if exists { r, err = pull(clonePath, auth) } else { r, err = clone(repo, clonePath, auth) } return } func getAuth(privateKeyPath string) (*gitssh.PublicKeys, error) { privateKey, err := ioutil.ReadFile(privateKeyPath) if err != nil { return nil, err } signer, err := ssh.ParsePrivateKey(privateKey) if err != nil { return nil, err } return &gitssh.PublicKeys{User: "git", Signer: signer}, nil } func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*git.Repository, error) { return git.PlainClone(clonePath, false, &git.CloneOptions{ URL: repo, Auth: auth, }) } func pull(clonePath string, auth *gitssh.PublicKeys) (*git.Repository, error) { r, err := git.PlainOpen(clonePath) if err != nil { return nil, err } w, err := r.Worktree() if err != nil { return nil, err } err = w.Pull(&git.PullOptions{ RemoteName: "origin", Auth: auth, }) if err == git.NoErrAlreadyUpToDate { return r, nil } // go-git doesn't have an error variable for "non-fast-forward update", so // this is the only way to detect it if strings.HasPrefix("non-fast-forward update", err.Error()) { return r, nil } return r, err } func dirExists(path string) (bool, error) { _, err := os.Stat(path) if os.IsNotExist(err) { return false, nil } return true, err } func Commit(message string, w *git.Worktree) (plumbing.Hash, error) { return w.Commit(message, &git.CommitOptions{ Author: &object.Signature{ Name: "Grafana Dashboard Manager", Email: "grafana@cozycloud.cc", When: time.Now(), }, }) } func Push(r *git.Repository, keyPath string) error { auth, err := getAuth(keyPath) if err != nil { return err } err = r.Push(&git.PushOptions{ Auth: auth, }) if err == git.NoErrAlreadyUpToDate { return nil } return err }