github.com/abayer/test-infra@v0.0.5/prow/pod-utils/clone/clone.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package clone 18 19 import ( 20 "bytes" 21 "fmt" 22 "os" 23 "os/exec" 24 "strings" 25 26 "github.com/sirupsen/logrus" 27 "k8s.io/test-infra/prow/kube" 28 ) 29 30 // Run clones the refs under the prescribed directory and optionally 31 // configures the git username and email in the repository as well. 32 func Run(refs *kube.Refs, dir, gitUserName, gitUserEmail string, env []string) Record { 33 logrus.WithFields(logrus.Fields{"refs": refs}).Info("Cloning refs") 34 record := Record{Refs: refs} 35 repositoryURI := fmt.Sprintf("https://github.com/%s/%s.git", refs.Org, refs.Repo) 36 if refs.CloneURI != "" { 37 repositoryURI = refs.CloneURI 38 } 39 cloneDir := PathForRefs(dir, refs) 40 41 commands := []cloneCommand{ 42 func() (string, string, error) { 43 return fmt.Sprintf("os.MkdirAll(%s, 0755)", cloneDir), "", os.MkdirAll(cloneDir, 0755) 44 }, 45 } 46 47 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "init")) 48 if gitUserName != "" { 49 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "config", "user.name", gitUserName)) 50 } 51 if gitUserEmail != "" { 52 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "config", "user.email", gitUserEmail)) 53 } 54 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "fetch", repositoryURI, "--tags", "--prune")) 55 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "fetch", repositoryURI, refs.BaseRef)) 56 57 var target string 58 if refs.BaseSHA != "" { 59 target = refs.BaseSHA 60 } else { 61 target = "FETCH_HEAD" 62 } 63 // we need to be "on" the target branch after the sync 64 // so we need to set the branch to point to the base ref, 65 // but we cannot update a branch we are on, so in case we 66 // are on the branch we are syncing, we check out the SHA 67 // first and reset the branch second, then check out the 68 // branch we just reset to be in the correct final state 69 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "checkout", target)) 70 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "branch", "--force", refs.BaseRef, target)) 71 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "checkout", refs.BaseRef)) 72 73 for _, prRef := range refs.Pulls { 74 ref := fmt.Sprintf("pull/%d/head", prRef.Number) 75 if prRef.Ref != "" { 76 ref = prRef.Ref 77 } 78 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "fetch", repositoryURI, ref)) 79 var prCheckout string 80 if prRef.SHA != "" { 81 prCheckout = prRef.SHA 82 } else { 83 prCheckout = "FETCH_HEAD" 84 } 85 commands = append(commands, shellCloneCommand(cloneDir, env, "git", "merge", prCheckout)) 86 } 87 88 for _, command := range commands { 89 formattedCommand, output, err := command() 90 logrus.WithFields(logrus.Fields{"command": formattedCommand, "output": output, "error": err}).Info("Ran command") 91 message := "" 92 if err != nil { 93 message = err.Error() 94 record.Failed = true 95 } 96 record.Commands = append(record.Commands, Command{Command: formattedCommand, Output: output, Error: message}) 97 if err != nil { 98 break 99 } 100 } 101 102 return record 103 } 104 105 // PathForRefs determines the full path to where 106 // refs should be cloned 107 func PathForRefs(baseDir string, refs *kube.Refs) string { 108 var clonePath string 109 if refs.PathAlias != "" { 110 clonePath = refs.PathAlias 111 } else { 112 clonePath = fmt.Sprintf("github.com/%s/%s", refs.Org, refs.Repo) 113 } 114 return fmt.Sprintf("%s/src/%s", baseDir, clonePath) 115 } 116 117 type cloneCommand func() (string, string, error) 118 119 func shellCloneCommand(dir string, env []string, command string, args ...string) cloneCommand { 120 output := bytes.Buffer{} 121 cmd := exec.Command(command, args...) 122 cmd.Dir = dir 123 cmd.Env = append(cmd.Env, env...) 124 cmd.Stdout = &output 125 cmd.Stderr = &output 126 127 return func() (string, string, error) { 128 err := cmd.Run() 129 return strings.Join(append([]string{command}, args...), " "), output.String(), err 130 } 131 }