|  | @@ -10,87 +10,227 @@ import (
 | 
	
		
			
			| 10 | 10 |  	"github.com/sirupsen/logrus"
 | 
	
		
			
			| 11 | 11 |  	"golang.org/x/crypto/ssh"
 | 
	
		
			
			| 12 | 12 |  	gogit "gopkg.in/src-d/go-git.v4"
 | 
	
		
			
			|  | 13 | +	"gopkg.in/src-d/go-git.v4/plumbing"
 | 
	
		
			
			|  | 14 | +	"gopkg.in/src-d/go-git.v4/plumbing/object"
 | 
	
		
			
			|  | 15 | +	"gopkg.in/src-d/go-git.v4/plumbing/storer"
 | 
	
		
			
			| 13 | 16 |  	"gopkg.in/src-d/go-git.v4/plumbing/transport"
 | 
	
		
			
			| 14 | 17 |  	gitssh "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
 | 
	
		
			
			| 15 | 18 |  )
 | 
	
		
			
			| 16 | 19 |  
 | 
	
		
			
			|  | 20 | +type Repository struct {
 | 
	
		
			
			|  | 21 | +	Repo *gogit.Repository
 | 
	
		
			
			|  | 22 | +	cfg  config.GitSettings
 | 
	
		
			
			|  | 23 | +	auth *gitssh.PublicKeys
 | 
	
		
			
			|  | 24 | +}
 | 
	
		
			
			|  | 25 | +
 | 
	
		
			
			|  | 26 | +func NewRepository(cfg config.GitSettings) (r *Repository, invalidRepo bool, err error) {
 | 
	
		
			
			|  | 27 | +	repo, err := gogit.PlainOpen(cfg.ClonePath)
 | 
	
		
			
			|  | 28 | +	if err != nil {
 | 
	
		
			
			|  | 29 | +		if err == gogit.ErrRepositoryNotExists {
 | 
	
		
			
			|  | 30 | +			invalidRepo = true
 | 
	
		
			
			|  | 31 | +		} else {
 | 
	
		
			
			|  | 32 | +			return
 | 
	
		
			
			|  | 33 | +		}
 | 
	
		
			
			|  | 34 | +	}
 | 
	
		
			
			|  | 35 | +
 | 
	
		
			
			|  | 36 | +	r = &Repository{
 | 
	
		
			
			|  | 37 | +		Repo: repo,
 | 
	
		
			
			|  | 38 | +		cfg:  cfg,
 | 
	
		
			
			|  | 39 | +	}
 | 
	
		
			
			|  | 40 | +
 | 
	
		
			
			|  | 41 | +	err = r.getAuth()
 | 
	
		
			
			|  | 42 | +	return
 | 
	
		
			
			|  | 43 | +}
 | 
	
		
			
			|  | 44 | +
 | 
	
		
			
			| 17 | 45 |  // Sync synchronises a Git repository using a given configuration. "synchronises"
 | 
	
		
			
			| 18 | 46 |  // means that, if the repo from the configuration isn't already cloned in the
 | 
	
		
			
			| 19 |  | -// directory specified in the configuration, it will clone the repository,
 | 
	
		
			
			| 20 |  | -// else it will simply pull it in order to be up to date with the remote.
 | 
	
		
			
			|  | 47 | +// directory specified in the configuration, it will clone the repository (unless
 | 
	
		
			
			|  | 48 | +// if explicitely told not to), else it will simply pull it in order to be up to
 | 
	
		
			
			|  | 49 | +// date with the remote.
 | 
	
		
			
			| 21 | 50 |  // Returns the go-git representation of the repository.
 | 
	
		
			
			| 22 | 51 |  // Returns an error if there was an issue loading the SSH private key, checking
 | 
	
		
			
			| 23 | 52 |  // whether the clone path already exists, or synchronising the repo with the
 | 
	
		
			
			| 24 | 53 |  // remote.
 | 
	
		
			
			| 25 |  | -func Sync(cfg config.GitSettings) (r *gogit.Repository, err error) {
 | 
	
		
			
			| 26 |  | -	// Generate an authentication structure instance from the user and private
 | 
	
		
			
			| 27 |  | -	// key
 | 
	
		
			
			| 28 |  | -	auth, err := getAuth(cfg.User, cfg.PrivateKeyPath)
 | 
	
		
			
			| 29 |  | -	if err != nil {
 | 
	
		
			
			| 30 |  | -		return
 | 
	
		
			
			| 31 |  | -	}
 | 
	
		
			
			| 32 |  | -
 | 
	
		
			
			|  | 54 | +func (r *Repository) Sync(dontClone bool) (err error) {
 | 
	
		
			
			| 33 | 55 |  	// Check whether the clone path already exists
 | 
	
		
			
			| 34 |  | -	exists, err := dirExists(cfg.ClonePath)
 | 
	
		
			
			|  | 56 | +	exists, err := dirExists(r.cfg.ClonePath)
 | 
	
		
			
			| 35 | 57 |  	if err != nil {
 | 
	
		
			
			| 36 | 58 |  		return
 | 
	
		
			
			| 37 | 59 |  	}
 | 
	
		
			
			| 38 | 60 |  
 | 
	
		
			
			| 39 | 61 |  	// Check whether the clone path is a Git repository
 | 
	
		
			
			| 40 | 62 |  	var isRepo bool
 | 
	
		
			
			| 41 |  | -	if isRepo, err = dirExists(cfg.ClonePath + "/.git"); err != nil {
 | 
	
		
			
			|  | 63 | +	if isRepo, err = dirExists(r.cfg.ClonePath + "/.git"); err != nil {
 | 
	
		
			
			| 42 | 64 |  		return
 | 
	
		
			
			| 43 | 65 |  	} else if exists && !isRepo {
 | 
	
		
			
			| 44 | 66 |  		err = fmt.Errorf(
 | 
	
		
			
			| 45 | 67 |  			"%s already exists but is not a Git repository",
 | 
	
		
			
			| 46 |  | -			cfg.ClonePath,
 | 
	
		
			
			|  | 68 | +			r.cfg.ClonePath,
 | 
	
		
			
			| 47 | 69 |  		)
 | 
	
		
			
			| 48 | 70 |  
 | 
	
		
			
			| 49 | 71 |  		return
 | 
	
		
			
			| 50 | 72 |  	}
 | 
	
		
			
			| 51 | 73 |  
 | 
	
		
			
			| 52 | 74 |  	logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 53 |  | -		"repo":       cfg.User + "@" + cfg.URL,
 | 
	
		
			
			| 54 |  | -		"clone_path": cfg.ClonePath,
 | 
	
		
			
			|  | 75 | +		"repo":       r.cfg.User + "@" + r.cfg.URL,
 | 
	
		
			
			|  | 76 | +		"clone_path": r.cfg.ClonePath,
 | 
	
		
			
			| 55 | 77 |  		"pull":       exists,
 | 
	
		
			
			| 56 | 78 |  	}).Info("Synchronising the Git repository with the remote")
 | 
	
		
			
			| 57 | 79 |  
 | 
	
		
			
			| 58 | 80 |  	// If the clone path already exists, pull from the remote, else clone it.
 | 
	
		
			
			| 59 | 81 |  	if exists {
 | 
	
		
			
			| 60 |  | -		r, err = pull(cfg.ClonePath, auth)
 | 
	
		
			
			| 61 |  | -	} else {
 | 
	
		
			
			| 62 |  | -		r, err = clone(cfg.URL, cfg.ClonePath, auth)
 | 
	
		
			
			|  | 82 | +		err = r.pull()
 | 
	
		
			
			|  | 83 | +	} else if !dontClone {
 | 
	
		
			
			|  | 84 | +		err = r.clone()
 | 
	
		
			
			| 63 | 85 |  	}
 | 
	
		
			
			| 64 | 86 |  
 | 
	
		
			
			| 65 | 87 |  	return
 | 
	
		
			
			| 66 | 88 |  }
 | 
	
		
			
			| 67 | 89 |  
 | 
	
		
			
			|  | 90 | +// Push uses a given repository and configuration to push the local history of
 | 
	
		
			
			|  | 91 | +// the said repository to the remote, using an authentication structure instance
 | 
	
		
			
			|  | 92 | +// created from the configuration to authenticate on the remote.
 | 
	
		
			
			|  | 93 | +// Returns with an error if there was an issue creating the authentication
 | 
	
		
			
			|  | 94 | +// structure instance or pushing to the remote. In the latter case, if the error
 | 
	
		
			
			|  | 95 | +// is a known non-error, doesn't return any error.
 | 
	
		
			
			|  | 96 | +func (r *Repository) Push() (err error) {
 | 
	
		
			
			|  | 97 | +	logrus.WithFields(logrus.Fields{
 | 
	
		
			
			|  | 98 | +		"repo":       r.cfg.User + "@" + r.cfg.URL,
 | 
	
		
			
			|  | 99 | +		"clone_path": r.cfg.ClonePath,
 | 
	
		
			
			|  | 100 | +	}).Info("Pushing to the remote")
 | 
	
		
			
			|  | 101 | +
 | 
	
		
			
			|  | 102 | +	// Push to remote
 | 
	
		
			
			|  | 103 | +	if err = r.Repo.Push(&gogit.PushOptions{
 | 
	
		
			
			|  | 104 | +		Auth: r.auth,
 | 
	
		
			
			|  | 105 | +	}); err != nil {
 | 
	
		
			
			|  | 106 | +		// Check error against known non-errors
 | 
	
		
			
			|  | 107 | +		err = checkRemoteErrors(err, logrus.Fields{
 | 
	
		
			
			|  | 108 | +			"repo":       r.cfg.User + "@" + r.cfg.URL,
 | 
	
		
			
			|  | 109 | +			"clone_path": r.cfg.ClonePath,
 | 
	
		
			
			|  | 110 | +			"error":      err,
 | 
	
		
			
			|  | 111 | +		})
 | 
	
		
			
			|  | 112 | +	}
 | 
	
		
			
			|  | 113 | +
 | 
	
		
			
			|  | 114 | +	return err
 | 
	
		
			
			|  | 115 | +}
 | 
	
		
			
			|  | 116 | +
 | 
	
		
			
			|  | 117 | +func (r *Repository) GetLatestCommit() (*object.Commit, error) {
 | 
	
		
			
			|  | 118 | +	// Retrieve latest hash
 | 
	
		
			
			|  | 119 | +	refs, err := r.Repo.References()
 | 
	
		
			
			|  | 120 | +	if err != nil {
 | 
	
		
			
			|  | 121 | +		return nil, err
 | 
	
		
			
			|  | 122 | +	}
 | 
	
		
			
			|  | 123 | +
 | 
	
		
			
			|  | 124 | +	ref, err := refs.Next()
 | 
	
		
			
			|  | 125 | +	if err != nil {
 | 
	
		
			
			|  | 126 | +		return nil, err
 | 
	
		
			
			|  | 127 | +	}
 | 
	
		
			
			|  | 128 | +
 | 
	
		
			
			|  | 129 | +	hash := ref.Hash()
 | 
	
		
			
			|  | 130 | +	return r.Repo.CommitObject(hash)
 | 
	
		
			
			|  | 131 | +}
 | 
	
		
			
			|  | 132 | +
 | 
	
		
			
			|  | 133 | +func (r *Repository) Log(fromHash string) (object.CommitIter, error) {
 | 
	
		
			
			|  | 134 | +	hash := plumbing.NewHash(fromHash)
 | 
	
		
			
			|  | 135 | +
 | 
	
		
			
			|  | 136 | +	return r.Repo.Log(&gogit.LogOptions{
 | 
	
		
			
			|  | 137 | +		From: hash,
 | 
	
		
			
			|  | 138 | +	})
 | 
	
		
			
			|  | 139 | +}
 | 
	
		
			
			|  | 140 | +
 | 
	
		
			
			|  | 141 | +func (r *Repository) LineCountsDeltasIgnoreManagerCommits(
 | 
	
		
			
			|  | 142 | +	from *object.Commit, to *object.Commit,
 | 
	
		
			
			|  | 143 | +) (lineCountsDeltas map[string]int, err error) {
 | 
	
		
			
			|  | 144 | +	// We expect "from" to be the oldest commit, and "to" to be the most recent
 | 
	
		
			
			|  | 145 | +	// one. Because Log() works the other way (in anti-chronological order),
 | 
	
		
			
			|  | 146 | +	// we call it with "to" and not "from" because, that way, we'll go from "to"
 | 
	
		
			
			|  | 147 | +	// to "from".
 | 
	
		
			
			|  | 148 | +	iter, err := r.Log(to.Hash.String())
 | 
	
		
			
			|  | 149 | +	if err != nil {
 | 
	
		
			
			|  | 150 | +		return
 | 
	
		
			
			|  | 151 | +	}
 | 
	
		
			
			|  | 152 | +
 | 
	
		
			
			|  | 153 | +	lineCountsDeltas = make(map[string]int)
 | 
	
		
			
			|  | 154 | +	err = iter.ForEach(func(commit *object.Commit) error {
 | 
	
		
			
			|  | 155 | +		if commit.Author.Email == r.cfg.CommitsAuthor.Email {
 | 
	
		
			
			|  | 156 | +			return nil
 | 
	
		
			
			|  | 157 | +		}
 | 
	
		
			
			|  | 158 | +
 | 
	
		
			
			|  | 159 | +		if commit.Hash.String() == from.Hash.String() {
 | 
	
		
			
			|  | 160 | +			return storer.ErrStop
 | 
	
		
			
			|  | 161 | +		}
 | 
	
		
			
			|  | 162 | +
 | 
	
		
			
			|  | 163 | +		stats, err := commit.Stats()
 | 
	
		
			
			|  | 164 | +		if err != nil {
 | 
	
		
			
			|  | 165 | +			return err
 | 
	
		
			
			|  | 166 | +		}
 | 
	
		
			
			|  | 167 | +
 | 
	
		
			
			|  | 168 | +		for _, stat := range stats {
 | 
	
		
			
			|  | 169 | +			// We're getting recent -> old additions and deletions. Because we
 | 
	
		
			
			|  | 170 | +			// want the opposite (old -> recent), we must invert the sign of both.
 | 
	
		
			
			|  | 171 | +			lineCountsDeltas[stat.Name] = stat.Deletion - stat.Addition
 | 
	
		
			
			|  | 172 | +		}
 | 
	
		
			
			|  | 173 | +
 | 
	
		
			
			|  | 174 | +		return nil
 | 
	
		
			
			|  | 175 | +	})
 | 
	
		
			
			|  | 176 | +
 | 
	
		
			
			|  | 177 | +	return
 | 
	
		
			
			|  | 178 | +}
 | 
	
		
			
			|  | 179 | +
 | 
	
		
			
			|  | 180 | +func GetFilesLineCountsAtCommit(commit *object.Commit) (map[string]int, error) {
 | 
	
		
			
			|  | 181 | +	tree, err := commit.Tree()
 | 
	
		
			
			|  | 182 | +	if err != nil {
 | 
	
		
			
			|  | 183 | +		return nil, err
 | 
	
		
			
			|  | 184 | +	}
 | 
	
		
			
			|  | 185 | +
 | 
	
		
			
			|  | 186 | +	lineCounts := make(map[string]int)
 | 
	
		
			
			|  | 187 | +
 | 
	
		
			
			|  | 188 | +	files := tree.Files()
 | 
	
		
			
			|  | 189 | +
 | 
	
		
			
			|  | 190 | +	var lines []string
 | 
	
		
			
			|  | 191 | +	err = files.ForEach(func(file *object.File) error {
 | 
	
		
			
			|  | 192 | +		lines, err = file.Lines()
 | 
	
		
			
			|  | 193 | +		if err != nil {
 | 
	
		
			
			|  | 194 | +			return err
 | 
	
		
			
			|  | 195 | +		}
 | 
	
		
			
			|  | 196 | +
 | 
	
		
			
			|  | 197 | +		lineCounts[file.Name] = len(lines)
 | 
	
		
			
			|  | 198 | +
 | 
	
		
			
			|  | 199 | +		return nil
 | 
	
		
			
			|  | 200 | +	})
 | 
	
		
			
			|  | 201 | +
 | 
	
		
			
			|  | 202 | +	return lineCounts, err
 | 
	
		
			
			|  | 203 | +}
 | 
	
		
			
			|  | 204 | +
 | 
	
		
			
			| 68 | 205 |  // getAuth returns the authentication structure instance needed to authenticate
 | 
	
		
			
			| 69 | 206 |  // on the remote, using a given user and private key path.
 | 
	
		
			
			| 70 | 207 |  // Returns an error if there was an issue reading the private key file or
 | 
	
		
			
			| 71 | 208 |  // parsing it.
 | 
	
		
			
			| 72 |  | -func getAuth(user string, privateKeyPath string) (*gitssh.PublicKeys, error) {
 | 
	
		
			
			| 73 |  | -	privateKey, err := ioutil.ReadFile(privateKeyPath)
 | 
	
		
			
			|  | 209 | +func (r *Repository) getAuth() error {
 | 
	
		
			
			|  | 210 | +	privateKey, err := ioutil.ReadFile(r.cfg.PrivateKeyPath)
 | 
	
		
			
			| 74 | 211 |  	if err != nil {
 | 
	
		
			
			| 75 |  | -		return nil, err
 | 
	
		
			
			|  | 212 | +		return err
 | 
	
		
			
			| 76 | 213 |  	}
 | 
	
		
			
			| 77 | 214 |  
 | 
	
		
			
			| 78 | 215 |  	signer, err := ssh.ParsePrivateKey(privateKey)
 | 
	
		
			
			| 79 | 216 |  	if err != nil {
 | 
	
		
			
			| 80 |  | -		return nil, err
 | 
	
		
			
			|  | 217 | +		return err
 | 
	
		
			
			| 81 | 218 |  	}
 | 
	
		
			
			| 82 | 219 |  
 | 
	
		
			
			| 83 |  | -	return &gitssh.PublicKeys{User: user, Signer: signer}, nil
 | 
	
		
			
			|  | 220 | +	r.auth = &gitssh.PublicKeys{User: r.cfg.User, Signer: signer}
 | 
	
		
			
			|  | 221 | +	return nil
 | 
	
		
			
			| 84 | 222 |  }
 | 
	
		
			
			| 85 | 223 |  
 | 
	
		
			
			| 86 | 224 |  // clone clones a Git repository into a given path, using a given auth.
 | 
	
		
			
			| 87 | 225 |  // Returns the go-git representation of the Git repository.
 | 
	
		
			
			| 88 | 226 |  // Returns an error if there was an issue cloning the repository.
 | 
	
		
			
			| 89 |  | -func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*gogit.Repository, error) {
 | 
	
		
			
			| 90 |  | -	return gogit.PlainClone(clonePath, false, &gogit.CloneOptions{
 | 
	
		
			
			| 91 |  | -		URL:  repo,
 | 
	
		
			
			| 92 |  | -		Auth: auth,
 | 
	
		
			
			|  | 227 | +func (r *Repository) clone() (err error) {
 | 
	
		
			
			|  | 228 | +	r.Repo, err = gogit.PlainClone(r.cfg.ClonePath, false, &gogit.CloneOptions{
 | 
	
		
			
			|  | 229 | +		URL:  r.cfg.URL,
 | 
	
		
			
			|  | 230 | +		Auth: r.auth,
 | 
	
		
			
			| 93 | 231 |  	})
 | 
	
		
			
			|  | 232 | +
 | 
	
		
			
			|  | 233 | +	return err
 | 
	
		
			
			| 94 | 234 |  }
 | 
	
		
			
			| 95 | 235 |  
 | 
	
		
			
			| 96 | 236 |  // pull opens the repository located at a given path, and pulls it from the
 | 
	
	
		
			
			|  | @@ -99,32 +239,34 @@ func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*gogit.Repos
 | 
	
		
			
			| 99 | 239 |  // Returns an error if there was an issue opening the repo, getting its work
 | 
	
		
			
			| 100 | 240 |  // tree or pulling from the remote. In the latter case, if the error is a known
 | 
	
		
			
			| 101 | 241 |  // non-error, doesn't return any error.
 | 
	
		
			
			| 102 |  | -func pull(clonePath string, auth *gitssh.PublicKeys) (*gogit.Repository, error) {
 | 
	
		
			
			|  | 242 | +func (r *Repository) pull() error {
 | 
	
		
			
			| 103 | 243 |  	// Open the repository
 | 
	
		
			
			| 104 |  | -	r, err := gogit.PlainOpen(clonePath)
 | 
	
		
			
			|  | 244 | +	repo, err := gogit.PlainOpen(r.cfg.ClonePath)
 | 
	
		
			
			| 105 | 245 |  	if err != nil {
 | 
	
		
			
			| 106 |  | -		return nil, err
 | 
	
		
			
			|  | 246 | +		return err
 | 
	
		
			
			| 107 | 247 |  	}
 | 
	
		
			
			| 108 | 248 |  
 | 
	
		
			
			| 109 | 249 |  	// Get its worktree
 | 
	
		
			
			| 110 |  | -	w, err := r.Worktree()
 | 
	
		
			
			|  | 250 | +	w, err := repo.Worktree()
 | 
	
		
			
			| 111 | 251 |  	if err != nil {
 | 
	
		
			
			| 112 |  | -		return nil, err
 | 
	
		
			
			|  | 252 | +		return err
 | 
	
		
			
			| 113 | 253 |  	}
 | 
	
		
			
			| 114 | 254 |  
 | 
	
		
			
			| 115 | 255 |  	// Pull from remote
 | 
	
		
			
			| 116 | 256 |  	if err = w.Pull(&gogit.PullOptions{
 | 
	
		
			
			| 117 | 257 |  		RemoteName: "origin",
 | 
	
		
			
			| 118 |  | -		Auth:       auth,
 | 
	
		
			
			|  | 258 | +		Auth:       r.auth,
 | 
	
		
			
			| 119 | 259 |  	}); err != nil {
 | 
	
		
			
			| 120 | 260 |  		// Check error against known non-errors
 | 
	
		
			
			| 121 | 261 |  		err = checkRemoteErrors(err, logrus.Fields{
 | 
	
		
			
			| 122 |  | -			"clone_path": clonePath,
 | 
	
		
			
			|  | 262 | +			"clone_path": r.cfg.ClonePath,
 | 
	
		
			
			| 123 | 263 |  			"error":      err,
 | 
	
		
			
			| 124 | 264 |  		})
 | 
	
		
			
			| 125 | 265 |  	}
 | 
	
		
			
			| 126 | 266 |  
 | 
	
		
			
			| 127 |  | -	return r, err
 | 
	
		
			
			|  | 267 | +	r.Repo = repo
 | 
	
		
			
			|  | 268 | +
 | 
	
		
			
			|  | 269 | +	return err
 | 
	
		
			
			| 128 | 270 |  }
 | 
	
		
			
			| 129 | 271 |  
 | 
	
		
			
			| 130 | 272 |  // dirExists is a snippet checking if a directory exists on the disk.
 | 
	
	
		
			
			|  | @@ -141,39 +283,6 @@ func dirExists(path string) (bool, error) {
 | 
	
		
			
			| 141 | 283 |  	return true, err
 | 
	
		
			
			| 142 | 284 |  }
 | 
	
		
			
			| 143 | 285 |  
 | 
	
		
			
			| 144 |  | -// Push uses a given repository and configuration to push the local history of
 | 
	
		
			
			| 145 |  | -// the said repository to the remote, using an authentication structure instance
 | 
	
		
			
			| 146 |  | -// created from the configuration to authenticate on the remote.
 | 
	
		
			
			| 147 |  | -// Returns with an error if there was an issue creating the authentication
 | 
	
		
			
			| 148 |  | -// structure instance or pushing to the remote. In the latter case, if the error
 | 
	
		
			
			| 149 |  | -// is a known non-error, doesn't return any error.
 | 
	
		
			
			| 150 |  | -func Push(r *gogit.Repository, cfg config.GitSettings) error {
 | 
	
		
			
			| 151 |  | -	// Get the authentication structure instance
 | 
	
		
			
			| 152 |  | -	auth, err := getAuth(cfg.User, cfg.PrivateKeyPath)
 | 
	
		
			
			| 153 |  | -	if err != nil {
 | 
	
		
			
			| 154 |  | -		return err
 | 
	
		
			
			| 155 |  | -	}
 | 
	
		
			
			| 156 |  | -
 | 
	
		
			
			| 157 |  | -	logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 158 |  | -		"repo":       cfg.User + "@" + cfg.URL,
 | 
	
		
			
			| 159 |  | -		"clone_path": cfg.ClonePath,
 | 
	
		
			
			| 160 |  | -	}).Info("Pushing to the remote")
 | 
	
		
			
			| 161 |  | -
 | 
	
		
			
			| 162 |  | -	// Push to remote
 | 
	
		
			
			| 163 |  | -	if err = r.Push(&gogit.PushOptions{
 | 
	
		
			
			| 164 |  | -		Auth: auth,
 | 
	
		
			
			| 165 |  | -	}); err != nil {
 | 
	
		
			
			| 166 |  | -		// Check error against known non-errors
 | 
	
		
			
			| 167 |  | -		err = checkRemoteErrors(err, logrus.Fields{
 | 
	
		
			
			| 168 |  | -			"repo":       cfg.User + "@" + cfg.URL,
 | 
	
		
			
			| 169 |  | -			"clone_path": cfg.ClonePath,
 | 
	
		
			
			| 170 |  | -			"error":      err,
 | 
	
		
			
			| 171 |  | -		})
 | 
	
		
			
			| 172 |  | -	}
 | 
	
		
			
			| 173 |  | -
 | 
	
		
			
			| 174 |  | -	return err
 | 
	
		
			
			| 175 |  | -}
 | 
	
		
			
			| 176 |  | -
 | 
	
		
			
			| 177 | 286 |  // processRemoteErrors checks an error against known non-errors returned when
 | 
	
		
			
			| 178 | 287 |  // communicating with the remote. If the error is a non-error, returns nil and
 | 
	
		
			
			| 179 | 288 |  // logs it with the provided fields. If not, returns the error.
 |