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
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, " ")) |
|
}
|
|
|