Skip to content

Commit

Permalink
oc start-build --from-repo now uses clone+checkout
Browse files Browse the repository at this point in the history
This allows us to handle submodules.  However, it takes up a bit more
resources.  This shouldn't be a problem - even the Linux kernel only
took about 3 seconds to clone to another local directory.
  • Loading branch information
oatmealraisin committed Nov 3, 2016
1 parent 029c0dc commit 5d22f46
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 27 deletions.
85 changes: 63 additions & 22 deletions pkg/cmd/cli/cmd/startbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,9 @@ func streamPathToBuild(repo git.Repository, in io.Reader, out io.Writer, client
if len(options.Commit) > 0 {
commit = options.Commit
}
info, gitErr := gitRefInfo(repo, clean, commit)

info, gitErr := gitRefInfo(repo, path, commit)

if gitErr == nil {
options.Commit = info.GitSourceRevision.Commit
options.Message = info.GitSourceRevision.Message
Expand All @@ -468,36 +470,75 @@ func streamPathToBuild(repo git.Repository, in io.Reader, out io.Writer, client
glog.V(6).Infof("Unable to read Git info from %q: %v", clean, gitErr)
}

// NOTE: It's important that this stays false unless we change the
// path to something else, otherwise we will delete whatever path the
// user provided.
var usedTempDir bool = false
var tempDirectory string = ""

if asRepo {

var contextDir string = ""
fmt.Fprintf(out, "Uploading %q at commit %q as binary input for the build ...\n", clean, commit)
if gitErr != nil {
return nil, fmt.Errorf("the directory %q is not a valid Git repository: %v", clean, gitErr)
}
pr, pw := io.Pipe()
go func() {
if err := repo.Archive(clean, options.Commit, "tar.gz", pw); err != nil {
pw.CloseWithError(fmt.Errorf("unable to create Git archive of %q for build: %v", clean, err))
} else {
pw.CloseWithError(io.EOF)
}
}()
r = pr

// If the user doesn't give us the root directory of the Git repo,
// we still want the command to work. However, as this may be
// unintended, we warn them.
if gitRootDir, err := repo.GetRootDir(path); filepath.Clean(gitRootDir) != filepath.Clean(path) && err == nil {
fmt.Fprintf(out, "WARNING: Using root dir %s for Git repository\n", gitRootDir)
contextDir, _ = filepath.Rel(gitRootDir, path)
path = gitRootDir
}

// Create a temp directory to move the repo contents to
tempDirectory, err := ioutil.TempDir(os.TempDir(), "oc_cloning_"+options.Commit)
if err != nil {
return nil, err
}

// We only want to grab the contents of the specified commit, with
// submodules included
cloneOptions := []string{"--recursive"}
if verbose := glog.V(3); !verbose {
cloneOptions = append(cloneOptions, "--quiet")
}

// Clone the repository to a temp directory for future tar-ing
if err := repo.CloneWithOptions(tempDirectory, path, cloneOptions...); err != nil {
return nil, err
}
if err := repo.Checkout(tempDirectory, commit); err != nil {
return nil, err
}

// We'll continue to use tar on the temp directory
path = filepath.Join(tempDirectory, contextDir)

usedTempDir = true

} else {
fmt.Fprintf(out, "Uploading directory %q as binary input for the build ...\n", clean)

pr, pw := io.Pipe()
go func() {
w := gzip.NewWriter(pw)
if err := tar.New().CreateTarStream(path, false, w); err != nil {
pw.CloseWithError(err)
} else {
w.Close()
pw.CloseWithError(io.EOF)
}
}()
r = pr
}

pr, pw := io.Pipe()
go func() {
w := gzip.NewWriter(pw)
if err := tar.New().CreateTarStream(path, false, w); err != nil {
pw.CloseWithError(err)
} else {
w.Close()
pw.CloseWithError(io.EOF)
}

if usedTempDir {
os.RemoveAll(tempDirectory)
}
}()
r = pr

} else {
f, err := os.Open(path)
if err != nil {
Expand Down
18 changes: 13 additions & 5 deletions test/extended/builds/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package builds

import (
"fmt"
"os/exec"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -86,6 +88,8 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
})

g.Describe("binary builds", func() {
var commit string

g.It("should accept --from-file as input", func() {
g.By("starting the build with a Dockerfile")
br, err := exutil.StartBuildAndWait(oc, "sample-build", fmt.Sprintf("--from-file=%s", exampleGemfile))
Expand Down Expand Up @@ -127,17 +131,20 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {

g.It("should accept --from-repo with --commit as input", func() {
g.By("starting the build with a Git repository")
// NOTE: This actually takes the commit from the origin repository. If the
// test-build-app changes, this commit has to be bumped.
br, err := exutil.StartBuildAndWait(oc, "sample-build", "--commit=f0f3834", fmt.Sprintf("--from-repo=%s", exampleBuild))
gitCmd := exec.Command("git", "rev-parse", "HEAD~1")
gitCmd.Dir = exampleBuild
commitByteArray, err := gitCmd.CombinedOutput()
commit = strings.TrimSpace(string(commitByteArray[:]))
o.Expect(err).NotTo(o.HaveOccurred())
br, err := exutil.StartBuildAndWait(oc, "sample-build", fmt.Sprintf("--commit=%s", commit), fmt.Sprintf("--from-repo=%s", exampleBuild))
br.AssertSuccess()
buildLog, err := br.Logs()
o.Expect(err).NotTo(o.HaveOccurred())

o.Expect(br.StartBuildStdErr).To(o.ContainSubstring("Uploading"))
o.Expect(br.StartBuildStdErr).To(o.ContainSubstring(`at commit "f0f3834"`))
o.Expect(br.StartBuildStdErr).To(o.ContainSubstring(fmt.Sprintf("at commit \"%s\"", commit)))
o.Expect(br.StartBuildStdErr).To(o.ContainSubstring("as binary input for the build ..."))
o.Expect(buildLog).To(o.ContainSubstring(`"commit":"f0f38342e53eac2a6995acca81d06bd9dd6d4964"`))
o.Expect(buildLog).To(o.ContainSubstring(fmt.Sprintf("\"commit\":\"%s\"", commit)))
o.Expect(buildLog).To(o.ContainSubstring("Your bundle is complete"))
})

Expand Down Expand Up @@ -186,6 +193,7 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
if err != nil || len(out) == 0 {
return false, nil
}

buildName = out
return true, nil
})
Expand Down

0 comments on commit 5d22f46

Please sign in to comment.