You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

146 lines
4.7 KiB

/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package clone
import (
"bytes"
"fmt"
"os/exec"
"strings"
"github.com/sirupsen/logrus"
"k8s.io/test-infra/prow/kube"
)
// Run clones the refs under the prescribed directory and optionally
// configures the git username and email in the repository as well.
func Run(refs kube.Refs, dir, gitUserName, gitUserEmail, cookiePath string, env []string) Record {
logrus.WithFields(logrus.Fields{"refs": refs}).Info("Cloning refs")
record := Record{Refs: refs}
for _, command := range commandsForRefs(refs, dir, gitUserName, gitUserEmail, cookiePath, env) {
formattedCommand, output, err := command.run()
logrus.WithFields(logrus.Fields{"command": formattedCommand, "output": output, "error": err}).Info("Ran command")
message := ""
if err != nil {
message = err.Error()
record.Failed = true
}
record.Commands = append(record.Commands, Command{Command: formattedCommand, Output: output, Error: message})
if err != nil {
break
}
}
return record
}
// PathForRefs determines the full path to where
// refs should be cloned
func PathForRefs(baseDir string, refs kube.Refs) string {
var clonePath string
if refs.PathAlias != "" {
clonePath = refs.PathAlias
} else {
clonePath = fmt.Sprintf("github.com/%s/%s", refs.Org, refs.Repo)
}
return fmt.Sprintf("%s/src/%s", baseDir, clonePath)
}
func commandsForRefs(refs kube.Refs, dir, gitUserName, gitUserEmail, cookiePath string, env []string) []cloneCommand {
repositoryURI := fmt.Sprintf("https://github.com/%s/%s.git", refs.Org, refs.Repo)
if refs.CloneURI != "" {
repositoryURI = refs.CloneURI
}
cloneDir := PathForRefs(dir, refs)
commands := []cloneCommand{{"/", env, "mkdir", []string{"-p", cloneDir}}}
gitCommand := func(args ...string) cloneCommand {
return cloneCommand{dir: cloneDir, env: env, command: "git", args: args}
}
commands = append(commands, gitCommand("init"))
if gitUserName != "" {
commands = append(commands, gitCommand("config", "user.name", gitUserName))
}
if gitUserEmail != "" {
commands = append(commands, gitCommand("config", "user.email", gitUserEmail))
}
if cookiePath != "" {
commands = append(commands, gitCommand("config", "http.cookiefile", cookiePath))
}
commands = append(commands, gitCommand("fetch", repositoryURI, "--tags", "--prune"))
commands = append(commands, gitCommand("fetch", repositoryURI, refs.BaseRef))
// unless the user specifically asks us not to, init submodules
if !refs.SkipSubmodules {
commands = append(commands, gitCommand("submodule", "update", "--init", "--recursive"))
}
var target string
if refs.BaseSHA != "" {
target = refs.BaseSHA
} else {
target = "FETCH_HEAD"
}
// we need to be "on" the target branch after the sync
// so we need to set the branch to point to the base ref,
// but we cannot update a branch we are on, so in case we
// are on the branch we are syncing, we check out the SHA
// first and reset the branch second, then check out the
// branch we just reset to be in the correct final state
commands = append(commands, gitCommand("checkout", target))
commands = append(commands, gitCommand("branch", "--force", refs.BaseRef, target))
commands = append(commands, gitCommand("checkout", refs.BaseRef))
for _, prRef := range refs.Pulls {
ref := fmt.Sprintf("pull/%d/head", prRef.Number)
if prRef.Ref != "" {
ref = prRef.Ref
}
commands = append(commands, gitCommand("fetch", repositoryURI, ref))
var prCheckout string
if prRef.SHA != "" {
prCheckout = prRef.SHA
} else {
prCheckout = "FETCH_HEAD"
}
commands = append(commands, gitCommand("merge", prCheckout))
}
return commands
}
type cloneCommand struct {
dir string
env []string
command string
args []string
}
func (c *cloneCommand) run() (string, string, error) {
output := bytes.Buffer{}
cmd := exec.Command(c.command, c.args...)
cmd.Dir = c.dir
cmd.Env = append(cmd.Env, c.env...)
cmd.Stdout = &output
cmd.Stderr = &output
err := cmd.Run()
return strings.Join(append([]string{c.command}, c.args...), " "), output.String(), err
}
func (c *cloneCommand) String() string {
return fmt.Sprintf("PWD=%s %s %s %s", c.dir, strings.Join(c.env, " "), c.command, strings.Join(c.env, " "))
}