/
helpers.go
151 lines (143 loc) · 4.51 KB
/
helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package gits
import (
"fmt"
"os"
"os/user"
"strings"
"github.com/jenkins-x/jx/pkg/util"
"github.com/jenkins-x/jx/pkg/log"
"github.com/pkg/errors"
)
// EnsureUserAndEmailSetup returns the user name and email for the gitter
// lazily setting them if they are blank either from the environment variables
// `GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL` or using default values
func EnsureUserAndEmailSetup(gitter Gitter) (string, string, error) {
userName, _ := gitter.Username("")
userEmail, _ := gitter.Email("")
if userName == "" {
userName = os.Getenv("GIT_AUTHOR_NAME")
if userName == "" {
user, err := user.Current()
if err == nil && user != nil {
userName = user.Username
}
}
if userName == "" {
userName = "jenkins-x-bot"
}
err := gitter.SetUsername("", userName)
if err != nil {
return userName, userEmail, errors.Wrapf(err, "Failed to set the git username to %s", userName)
}
}
if userEmail == "" {
userEmail = os.Getenv("GIT_AUTHOR_EMAIL")
if userEmail == "" {
userEmail = "jenkins-x@googlegroups.com"
}
err := gitter.SetEmail("", userEmail)
if err != nil {
return userName, userEmail, errors.Wrapf(err, "Failed to set the git email to %s", userEmail)
}
}
return userName, userEmail, nil
}
// Unshallow converts a shallow git repo (one cloned with --depth=n) into one has full depth for the current branch
// and all tags. Note that remote branches are still not fetched,
// you need to do this manually. It checks if the repo is shallow or not before trying to unshallow it.
func Unshallow(dir string, gitter Gitter) error {
shallow, err := gitter.IsShallow(dir)
if err != nil {
return err
}
if shallow {
if err := gitter.FetchUnshallow(dir); err != nil {
return err
}
if err := gitter.FetchTags(dir); err != nil {
return err
}
log.Infof("Converted %s to an unshallow repository\n", dir)
return nil
}
return nil
}
// FetchAndMergeSHAs merges any SHAs into the baseBranch which has a tip of baseSha,
// fetching the commits from remote for the git repo in dir. It will try to fetch individual commits (
// if the remote repo supports it - see https://github.
// com/git/git/commit/68ee628932c2196742b77d2961c5e16360734a62) otherwise it uses git remote update to pull down the
// whole repo.
func FetchAndMergeSHAs(SHAs []string, baseBranch string, baseSha string, remote string, dir string,
gitter Gitter, verbose bool) error {
refspecs := make([]string, 0)
for _, sha := range SHAs {
refspecs = append(refspecs, fmt.Sprintf("%s:", sha))
}
refspecs = append(refspecs, fmt.Sprintf("%s:", baseSha))
// First lets make sure we have the commits - remember that this may be a shallow clone
err := gitter.FetchBranchUnshallow(dir, remote, refspecs...)
if err != nil {
// Unshallow fetch failed, so do a full unshallow
// First ensure we actually have the branch refs
err := gitter.FetchBranch(dir, remote, refspecs...)
if err != nil {
// This can be caused by git not being configured to allow fetching individual SHAs
// There is not a nice way to solve this except to attempt to do a full fetch
err = gitter.RemoteUpdate(dir)
if err != nil {
return errors.Wrapf(err, "updating remote %s", remote)
}
if verbose {
log.Infof("ran %s in %s\n", util.ColorInfo("git remote update"), dir)
}
}
if verbose {
log.Infof("ran git fetch %s %s in %s\n", remote, strings.Join(refspecs, " "), dir)
}
err = Unshallow(dir, gitter)
if err != nil {
return errors.WithStack(err)
}
if verbose {
log.Infof("Unshallowed git repo in %s\n", dir)
}
} else {
if verbose {
log.Infof("ran git fetch --unshallow %s %s in %s\n", remote, strings.Join(refspecs, " "), dir)
}
}
// Ensure we are on baseBranch
err = gitter.Checkout(dir, baseBranch)
if err != nil {
return errors.Wrapf(err, "checking out %s", baseBranch)
}
if verbose {
log.Infof("ran git checkout %s in %s\n", baseBranch, dir)
}
// Ensure we are on the right revision
err = gitter.ResetHard(dir, baseSha)
if err != nil {
errors.Wrapf(err, "resetting %s to %s", baseBranch, baseSha)
}
if verbose {
log.Infof("ran git reset --hard %s in %s\n", baseSha, dir)
}
err = gitter.CleanForce(dir, ".")
if err != nil {
return errors.Wrapf(err, "cleaning up the git repo")
}
if verbose {
log.Infof("ran clean --force -d . in %s\n", dir)
}
// Now do the merges
for _, sha := range SHAs {
err := gitter.Merge(dir, sha)
if err != nil {
return errors.Wrapf(err, "merging %s into master", sha)
}
if verbose {
log.Infof("ran git merge %s in %s\n", sha, dir)
}
}
return nil
}