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