mirror of https://github.com/docker/cli.git
200 lines
5.7 KiB
Go
200 lines
5.7 KiB
Go
package image
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/cli/internal/test"
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/gotestyourself/gotestyourself/assert"
|
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
|
"github.com/gotestyourself/gotestyourself/fs"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
|
dest, err := ioutil.TempDir("", "test-build-compress-dest")
|
|
assert.NilError(t, err)
|
|
defer os.RemoveAll(dest)
|
|
|
|
var dockerfileName string
|
|
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
buffer := new(bytes.Buffer)
|
|
tee := io.TeeReader(context, buffer)
|
|
|
|
assert.NilError(t, archive.Untar(tee, dest, nil))
|
|
dockerfileName = options.Dockerfile
|
|
|
|
header := buffer.Bytes()[:10]
|
|
assert.Check(t, is.Equal(archive.Gzip, archive.DetectCompression(header)))
|
|
|
|
body := new(bytes.Buffer)
|
|
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
|
}
|
|
|
|
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
|
dockerfile := bytes.NewBufferString(`
|
|
FROM alpine:3.6
|
|
COPY foo /
|
|
`)
|
|
cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))
|
|
|
|
dir, err := ioutil.TempDir("", "test-build-compress")
|
|
assert.NilError(t, err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("some content"), 0644)
|
|
|
|
options := newBuildOptions()
|
|
options.compress = true
|
|
options.dockerfileName = "-"
|
|
options.context = dir
|
|
options.untrusted = true
|
|
|
|
err = runBuild(cli, options)
|
|
assert.NilError(t, err)
|
|
|
|
files, err := ioutil.ReadDir(dest)
|
|
assert.NilError(t, err)
|
|
actual := []string{}
|
|
for _, fileInfo := range files {
|
|
actual = append(actual, fileInfo.Name())
|
|
}
|
|
sort.Strings(actual)
|
|
assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "foo"}, actual))
|
|
}
|
|
|
|
func TestRunBuildDockerfileOutsideContext(t *testing.T) {
|
|
dir := fs.NewDir(t, t.Name(),
|
|
fs.WithFile("data", "data file"),
|
|
)
|
|
defer dir.Remove()
|
|
|
|
// Dockerfile outside of build-context
|
|
df := fs.NewFile(t, t.Name(),
|
|
fs.WithContent(`
|
|
FROM FOOBAR
|
|
COPY data /data
|
|
`),
|
|
)
|
|
defer df.Remove()
|
|
|
|
dest, err := ioutil.TempDir("", t.Name())
|
|
assert.NilError(t, err)
|
|
defer os.RemoveAll(dest)
|
|
|
|
var dockerfileName string
|
|
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
buffer := new(bytes.Buffer)
|
|
tee := io.TeeReader(context, buffer)
|
|
|
|
assert.NilError(t, archive.Untar(tee, dest, nil))
|
|
dockerfileName = options.Dockerfile
|
|
|
|
body := new(bytes.Buffer)
|
|
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
|
}
|
|
|
|
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
|
|
|
options := newBuildOptions()
|
|
options.context = dir.Path()
|
|
options.dockerfileName = df.Path()
|
|
options.untrusted = true
|
|
|
|
err = runBuild(cli, options)
|
|
assert.NilError(t, err)
|
|
|
|
files, err := ioutil.ReadDir(dest)
|
|
assert.NilError(t, err)
|
|
var actual []string
|
|
for _, fileInfo := range files {
|
|
actual = append(actual, fileInfo.Name())
|
|
}
|
|
sort.Strings(actual)
|
|
assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "data"}, actual))
|
|
}
|
|
|
|
// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that build contexts
|
|
// starting with `github.com/` are special-cased, and the build command attempts
|
|
// to clone the remote repo.
|
|
// TODO: test "context selection" logic directly when runBuild is refactored
|
|
// to support testing (ex: docker/cli#294)
|
|
func TestRunBuildFromGitHubSpecialCase(t *testing.T) {
|
|
cmd := NewBuildCommand(test.NewFakeCli(nil))
|
|
// Clone a small repo that exists so git doesn't prompt for credentials
|
|
cmd.SetArgs([]string{"github.com/docker/for-win"})
|
|
cmd.SetOutput(ioutil.Discard)
|
|
err := cmd.Execute()
|
|
assert.ErrorContains(t, err, "unable to prepare context")
|
|
assert.ErrorContains(t, err, "docker-build-git")
|
|
}
|
|
|
|
// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that a local directory
|
|
// starting with `github.com` takes precedence over the `github.com` special
|
|
// case.
|
|
func TestRunBuildFromLocalGitHubDir(t *testing.T) {
|
|
tmpDir, err := ioutil.TempDir("", "docker-build-from-local-dir-")
|
|
assert.NilError(t, err)
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
buildDir := filepath.Join(tmpDir, "github.com", "docker", "no-such-repository")
|
|
err = os.MkdirAll(buildDir, 0777)
|
|
assert.NilError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(buildDir, "Dockerfile"), []byte("FROM busybox\n"), 0644)
|
|
assert.NilError(t, err)
|
|
|
|
client := test.NewFakeCli(&fakeClient{})
|
|
cmd := NewBuildCommand(client)
|
|
cmd.SetArgs([]string{buildDir})
|
|
cmd.SetOutput(ioutil.Discard)
|
|
err = cmd.Execute()
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func TestRunBuildWithSymlinkedContext(t *testing.T) {
|
|
dockerfile := `
|
|
FROM alpine:3.6
|
|
RUN echo hello world
|
|
`
|
|
|
|
tmpDir := fs.NewDir(t, t.Name(),
|
|
fs.WithDir("context",
|
|
fs.WithFile("Dockerfile", dockerfile)),
|
|
fs.WithSymlink("context-link", "context"))
|
|
defer tmpDir.Remove()
|
|
|
|
files := []string{}
|
|
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
tarReader := tar.NewReader(context)
|
|
for {
|
|
hdr, err := tarReader.Next()
|
|
switch err {
|
|
case io.EOF:
|
|
body := new(bytes.Buffer)
|
|
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
|
case nil:
|
|
files = append(files, hdr.Name)
|
|
default:
|
|
return types.ImageBuildResponse{}, err
|
|
}
|
|
}
|
|
}
|
|
|
|
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
|
options := newBuildOptions()
|
|
options.context = tmpDir.Join("context-link")
|
|
options.untrusted = true
|
|
assert.NilError(t, runBuild(cli, options))
|
|
|
|
assert.DeepEqual(t, files, []string{"Dockerfile"})
|
|
}
|