-
Notifications
You must be signed in to change notification settings - Fork 787
/
git.go
176 lines (156 loc) · 5.42 KB
/
git.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package users
import (
"fmt"
"strings"
"github.com/jenkins-x/jx/v2/pkg/kube/naming"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/pkg/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"gopkg.in/src-d/go-git.v4/plumbing/object"
jenkinsv1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
"github.com/jenkins-x/jx-logging/pkg/log"
jenkninsv1client "github.com/jenkins-x/jx-api/pkg/client/clientset/versioned"
"github.com/jenkins-x/jx/v2/pkg/gits"
)
// GitUserResolver allows git users to be converted to Jenkins X users
type GitUserResolver struct {
GitProvider gits.GitProvider
JXClient jenkninsv1client.Interface
Namespace string
}
// GitSignatureAsUser resolves the signature to a Jenkins X User
func (r *GitUserResolver) GitSignatureAsUser(signature *object.Signature) (*jenkinsv1.User, error) {
// We can't resolve no info so shortcircuit
if signature.Name == "" && signature.Email == "" {
return nil, errors.Errorf("both name and email are empty")
}
gitUser := &gits.GitUser{
Email: signature.Email,
Name: signature.Name,
}
return r.Resolve(gitUser)
}
// GitUserSliceAsUserDetailsSlice resolves a slice of git users to a slice of Jenkins X User Details
func (r *GitUserResolver) GitUserSliceAsUserDetailsSlice(users []gits.GitUser) ([]jenkinsv1.UserDetails, error) {
answer := []jenkinsv1.UserDetails{}
for _, user := range users {
us := user
u, err := r.Resolve(&us)
if err != nil {
return nil, err
}
if u != nil {
answer = append(answer, u.Spec)
}
}
return answer, nil
}
// Resolve will convert the GitUser to a Jenkins X user and attempt to complete the user info by:
// * checking the user custom resources to see if the user is present there
// * making a call to the gitProvider
// as often user info is not complete in a git response
func (r *GitUserResolver) Resolve(user *gits.GitUser) (*jenkinsv1.User, error) {
if r == nil || user == nil {
return nil, nil
}
selectUsers := func(id string, users []jenkinsv1.User) (string, []jenkinsv1.User,
*jenkinsv1.User, error) {
var gitUser *gits.GitUser
if user.Login != "" {
gitUser = r.GitProvider.UserInfo(user.Login)
}
if gitUser == nil {
gitUser = user
}
possibles := make([]jenkinsv1.User, 0)
if gitUser == nil {
// annoyingly UserInfo swallows the error, so we recreate it!
log.Logger().Warnf("unable to find user with login %s from %s", user.Login, r.GitProvider.Kind())
} else if user.Email != "" {
// Don't do this if email is empty as otherwise we risk matching any users who have empty emails!
for _, u := range users {
if u.Spec.Email == gitUser.Email {
possibles = append(possibles, u)
}
}
}
new := r.GitUserToUser(gitUser)
login := gitUser.Login
if login == "" {
login = strings.Replace(gitUser.Name, " ", "-", -1)
login = strings.ToLower(login)
}
id = naming.ToValidName(login)
// Check if the user id is available, if not append "-<n>" where <n> is some integer
for i := 0; true; i++ {
_, err := r.JXClient.JenkinsV1().Users(r.Namespace).Get(id, v1.GetOptions{})
if k8serrors.IsNotFound(err) {
break
}
id = fmt.Sprintf("%s-%d", login, i)
}
new.Name = naming.ToValidName(id)
return id, possibles, new, nil
}
user.Login = naming.ToValidValue(user.Login)
return Resolve(user.Login, r.GitProviderKey(), r.JXClient, r.Namespace, selectUsers)
}
// UpdateUserFromPRAuthor will attempt to use the
func (r *GitUserResolver) UpdateUserFromPRAuthor(author *jenkinsv1.User, pullRequest *gits.GitPullRequest,
commits []*gits.GitCommit) (*jenkinsv1.User, error) {
if pullRequest != nil {
updated := false
if author != nil {
gitLogin := r.GitUserLogin(author)
if gitLogin == "" {
gitLogin = author.Spec.Login
}
for _, commit := range commits {
if commit.Author != nil && gitLogin == commit.Author.Login {
log.Logger().Info("Found commit author match for: " + author.
Spec.Login + " with email address: " + commit.Author.Email + "\n")
author.Spec.Email = commit.Author.Email
updated = true
break
}
}
}
if updated {
return r.JXClient.JenkinsV1().Users(r.Namespace).PatchUpdate(author)
}
}
return author, nil
}
// UserToGitUser performs type conversion from a Jenkins X User to a Git User
func (r *GitUserResolver) UserToGitUser(id string, user *jenkinsv1.User) *gits.GitUser {
return &gits.GitUser{
Login: id,
Email: user.Spec.Email,
Name: user.Spec.Name,
URL: user.Spec.URL,
AvatarURL: user.Spec.AvatarURL,
}
}
// GitUserToUser performs type conversion from a GitUser to a Jenkins X user,
// attaching the Git Provider account to Accounts
func (r *GitUserResolver) GitUserToUser(gitUser *gits.GitUser) *jenkinsv1.User {
user := CreateUser(r.Namespace, gitUser.Login, gitUser.Name, gitUser.Email)
return AddAccountReference(user, r.GitProviderKey(), gitUser.Login)
}
// GitUserLogin returns the login for the git provider, or an empty string if not found
func (r *GitUserResolver) GitUserLogin(user *jenkinsv1.User) string {
for _, a := range user.Spec.Accounts {
if a.Provider == r.GitProviderKey() {
return a.ID
}
}
return ""
}
// GitProviderKey returns the provider key for this GitUserResolver
func (r *GitUserResolver) GitProviderKey() string {
if r == nil || r.GitProvider == nil {
return ""
}
return fmt.Sprintf("jenkins.io/git-%s-userid", r.GitProvider.Kind())
}
// mergeGitUsers merges user1 into user2, replacing any that do not have empty values on user2 with those from user1