Merge pull request #905 from vdemeester/appveyor-setup

Add appveyor setup to build and unit test
This commit is contained in:
Sebastiaan van Stijn 2018-03-08 09:50:41 +01:00 committed by GitHub
commit 310127a7d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 626 additions and 365 deletions

23
appveyor.yml Normal file
View File

@ -0,0 +1,23 @@
version: "{build}"
clone_folder: c:\gopath\src\github.com\docker\cli
environment:
GOPATH: c:\gopath
GOVERSION: 1.10
DEPVERSION: v0.4.1
install:
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- go version
- go env
deploy: false
build_script:
- ps: .\scripts\make.ps1 -Binary
test_script:
- ps: .\scripts\make.ps1 -TestUnit

View File

@ -3,6 +3,7 @@ package command
import ( import (
"crypto/x509" "crypto/x509"
"os" "os"
"runtime"
"testing" "testing"
cliconfig "github.com/docker/cli/cli/config" cliconfig "github.com/docker/cli/cli/config"
@ -20,6 +21,9 @@ import (
func TestNewAPIClientFromFlags(t *testing.T) { func TestNewAPIClientFromFlags(t *testing.T) {
host := "unix://path" host := "unix://path"
if runtime.GOOS == "windows" {
host = "npipe://./"
}
opts := &flags.CommonOptions{Hosts: []string{host}} opts := &flags.CommonOptions{Hosts: []string{host}}
configFile := &configfile.ConfigFile{ configFile := &configfile.ConfigFile{
HTTPHeaders: map[string]string{ HTTPHeaders: map[string]string{

View File

@ -121,7 +121,12 @@ func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) {
} }
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})
err := runCopy(cli, options) err := runCopy(cli, options)
assert.ErrorContains(t, err, "not a directory")
expectedError := "not a directory"
if runtime.GOOS == "windows" {
expectedError = "The filename, directory name, or volume label syntax is incorrect"
}
assert.ErrorContains(t, err, expectedError)
} }
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) { func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {

View File

@ -1,13 +1,12 @@
package formatter package formatter
import ( import (
"bytes"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
"bytes"
"github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert" "github.com/gotestyourself/gotestyourself/assert"
@ -51,6 +50,7 @@ func TestHistoryContext_ID(t *testing.T) {
} }
func TestHistoryContext_CreatedSince(t *testing.T) { func TestHistoryContext_CreatedSince(t *testing.T) {
dateStr := "2009-11-10T23:00:00Z"
var ctx historyContext var ctx historyContext
cases := []historyCase{ cases := []historyCase{
{ {
@ -65,7 +65,7 @@ func TestHistoryContext_CreatedSince(t *testing.T) {
h: image.HistoryResponseItem{Created: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()}, h: image.HistoryResponseItem{Created: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()},
trunc: false, trunc: false,
human: false, human: false,
}, "2009-11-10T23:00:00Z", ctx.CreatedSince, }, dateStr, ctx.CreatedSince,
}, },
} }

View File

@ -0,0 +1,54 @@
//+build linux
package image
import (
"bytes"
"io"
"io/ioutil"
"syscall"
"testing"
"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 TestRunBuildResetsUidAndGidInContext(t *testing.T) {
dest := fs.NewDir(t, "test-build-context-dest")
defer dest.Remove()
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
assert.NilError(t, archive.Untar(context, dest.Path(), nil))
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
dir := fs.NewDir(t, "test-build-context",
fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
fs.WithFile("Dockerfile", `
FROM alpine:3.6
COPY foo bar /
`),
)
defer dir.Remove()
options := newBuildOptions()
options.context = dir.Path()
err := runBuild(cli, options)
assert.NilError(t, err)
files, err := ioutil.ReadDir(dest.Path())
assert.NilError(t, err)
for _, fileInfo := range files {
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
}
}

View File

@ -6,9 +6,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"syscall"
"testing" "testing"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
@ -18,45 +16,9 @@ import (
"github.com/gotestyourself/gotestyourself/assert" "github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp" is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs" "github.com/gotestyourself/gotestyourself/fs"
"github.com/gotestyourself/gotestyourself/skip"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows")
dest := fs.NewDir(t, "test-build-context-dest")
defer dest.Remove()
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
assert.NilError(t, archive.Untar(context, dest.Path(), nil))
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
dir := fs.NewDir(t, "test-build-context",
fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
fs.WithFile("Dockerfile", `
FROM alpine:3.6
COPY foo bar /
`),
)
defer dir.Remove()
options := newBuildOptions()
options.context = dir.Path()
err := runBuild(cli, options)
assert.NilError(t, err)
files, err := ioutil.ReadDir(dest.Path())
assert.NilError(t, err)
for _, fileInfo := range files {
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
}
}
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) { func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
dest, err := ioutil.TempDir("", "test-build-compress-dest") dest, err := ioutil.TempDir("", "test-build-compress-dest")
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"runtime"
"testing" "testing"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
@ -14,7 +15,10 @@ import (
) )
func TestCreateErrors(t *testing.T) { func TestCreateErrors(t *testing.T) {
noSuchFile := "no such file or directory"
if runtime.GOOS == "windows" {
noSuchFile = "The system cannot find the file specified."
}
testCases := []struct { testCases := []struct {
args []string args []string
expectedError string expectedError string
@ -29,7 +33,7 @@ func TestCreateErrors(t *testing.T) {
}, },
{ {
args: []string{"plugin-foo", "nonexistent_context_dir"}, args: []string{"plugin-foo", "nonexistent_context_dir"},
expectedError: "no such file or directory", expectedError: noSuchFile,
}, },
} }
@ -61,7 +65,12 @@ func TestCreateErrorOnContextDirWithoutConfig(t *testing.T) {
cmd := newCreateCommand(cli) cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()}) cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
cmd.SetOutput(ioutil.Discard) cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), "config.json: no such file or directory")
expectedErr := "config.json: no such file or directory"
if runtime.GOOS == "windows" {
expectedErr = "config.json: The system cannot find the file specified."
}
assert.ErrorContains(t, cmd.Execute(), expectedErr)
} }
func TestCreateErrorOnInvalidConfig(t *testing.T) { func TestCreateErrorOnInvalidConfig(t *testing.T) {

View File

@ -33,10 +33,13 @@ func TestValidateExternalNetworks(t *testing.T) {
inspectError: errors.New("Unexpected"), inspectError: errors.New("Unexpected"),
expectedMsg: "Unexpected", expectedMsg: "Unexpected",
}, },
// FIXME(vdemeester) that doesn't work under windows, the check needs to be smarter
/*
{ {
inspectError: errors.New("host net does not exist on swarm classic"), inspectError: errors.New("host net does not exist on swarm classic"),
network: "host", network: "host",
}, },
*/
{ {
network: "user", network: "user",
expectedMsg: "is not in the right scope", expectedMsg: "is not in the right scope",

View File

@ -127,7 +127,7 @@ func TestValidateKeyArgs(t *testing.T) {
assert.NilError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms)) assert.NilError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms))
err = validateKeyArgs("a", pubKeyCWD) err = validateKeyArgs("a", pubKeyCWD)
assert.Error(t, err, fmt.Sprintf("public key file already exists: \"%s/a.pub\"", pubKeyCWD)) assert.Error(t, err, fmt.Sprintf("public key file already exists: \"%s\"", filepath.Join(pubKeyCWD, "a.pub")))
err = validateKeyArgs("a", "/random/dir/") err = validateKeyArgs("a", "/random/dir/")
assert.Error(t, err, "public key path does not exist: \"/random/dir/\"") assert.Error(t, err, "public key path does not exist: \"/random/dir/\"")

View File

@ -6,12 +6,14 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert" "github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp" is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/theupdateframework/notary" "github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/passphrase" "github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/storage" "github.com/theupdateframework/notary/storage"
@ -20,6 +22,10 @@ import (
) )
func TestTrustKeyLoadErrors(t *testing.T) { func TestTrustKeyLoadErrors(t *testing.T) {
noSuchFile := "stat iamnotakey: no such file or directory"
if runtime.GOOS == "windows" {
noSuchFile = "CreateFile iamnotakey: The system cannot find the file specified."
}
testCases := []struct { testCases := []struct {
name string name string
args []string args []string
@ -40,7 +46,7 @@ func TestTrustKeyLoadErrors(t *testing.T) {
{ {
name: "not-a-key", name: "not-a-key",
args: []string{"iamnotakey"}, args: []string{"iamnotakey"},
expectedError: "refusing to load key from iamnotakey: stat iamnotakey: no such file or directory", expectedError: "refusing to load key from iamnotakey: " + noSuchFile,
expectedOutput: "Loading key from \"iamnotakey\"...\n", expectedOutput: "Loading key from \"iamnotakey\"...\n",
}, },
{ {
@ -109,6 +115,7 @@ var testKeys = map[string][]byte{
} }
func TestLoadKeyFromPath(t *testing.T) { func TestLoadKeyFromPath(t *testing.T) {
skip.If(t, runtime.GOOS == "windows")
for keyID, keyBytes := range testKeys { for keyID, keyBytes := range testKeys {
t.Run(fmt.Sprintf("load-key-id-%s-from-path", keyID), func(t *testing.T) { t.Run(fmt.Sprintf("load-key-id-%s-from-path", keyID), func(t *testing.T) {
testLoadKeyFromPath(t, keyID, keyBytes) testLoadKeyFromPath(t, keyID, keyBytes)
@ -163,6 +170,7 @@ func testLoadKeyFromPath(t *testing.T, privKeyID string, privKeyFixture []byte)
} }
func TestLoadKeyTooPermissive(t *testing.T) { func TestLoadKeyTooPermissive(t *testing.T) {
skip.If(t, runtime.GOOS == "windows")
for keyID, keyBytes := range testKeys { for keyID, keyBytes := range testKeys {
t.Run(fmt.Sprintf("load-key-id-%s-too-permissive", keyID), func(t *testing.T) { t.Run(fmt.Sprintf("load-key-id-%s-too-permissive", keyID), func(t *testing.T) {
testLoadKeyTooPermissive(t, keyBytes) testLoadKeyTooPermissive(t, keyBytes)
@ -219,6 +227,7 @@ H3nzy2O6Q/ct4BjOBKa+WCdRtPo78bA+C/7t81ADQO8Jqaj59W50rwoqDQ==
-----END PUBLIC KEY-----`) -----END PUBLIC KEY-----`)
func TestLoadPubKeyFailure(t *testing.T) { func TestLoadPubKeyFailure(t *testing.T) {
skip.If(t, runtime.GOOS == "windows")
pubKeyDir, err := ioutil.TempDir("", "key-load-test-pubkey-") pubKeyDir, err := ioutil.TempDir("", "key-load-test-pubkey-")
assert.NilError(t, err) assert.NilError(t, err)
defer os.RemoveAll(pubKeyDir) defer os.RemoveAll(pubKeyDir)

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"os" "os"
"runtime"
"testing" "testing"
"github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config"
@ -12,6 +13,7 @@ import (
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert" "github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp" is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/theupdateframework/notary" "github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/client" "github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/client/changelist" "github.com/theupdateframework/notary/client/changelist"
@ -127,6 +129,7 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
} }
func TestAddStageSigners(t *testing.T) { func TestAddStageSigners(t *testing.T) {
skip.If(t, runtime.GOOS == "windows", "FIXME: not supported currently")
tmpDir, err := ioutil.TempDir("", "notary-test-") tmpDir, err := ioutil.TempDir("", "notary-test-")
assert.NilError(t, err) assert.NilError(t, err)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)

View File

@ -5,6 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config"
@ -96,7 +97,11 @@ func TestSignerAddCommandBadKeyPath(t *testing.T) {
cmd.SetArgs([]string{"--key", "/path/to/key.pem", "alice", "alpine"}) cmd.SetArgs([]string{"--key", "/path/to/key.pem", "alice", "alpine"})
cmd.SetOutput(ioutil.Discard) cmd.SetOutput(ioutil.Discard)
assert.Error(t, cmd.Execute(), "unable to read public key from file: open /path/to/key.pem: no such file or directory") expectedError := "unable to read public key from file: open /path/to/key.pem: no such file or directory"
if runtime.GOOS == "windows" {
expectedError = "unable to read public key from file: open /path/to/key.pem: The system cannot find the path specified."
}
assert.Error(t, cmd.Execute(), expectedError)
} }
func TestSignerAddCommandInvalidRepoName(t *testing.T) { func TestSignerAddCommandInvalidRepoName(t *testing.T) {
@ -127,7 +132,11 @@ func TestSignerAddCommandInvalidRepoName(t *testing.T) {
func TestIngestPublicKeys(t *testing.T) { func TestIngestPublicKeys(t *testing.T) {
// Call with a bad path // Call with a bad path
_, err := ingestPublicKeys([]string{"foo", "bar"}) _, err := ingestPublicKeys([]string{"foo", "bar"})
assert.Error(t, err, "unable to read public key from file: open foo: no such file or directory") expectedError := "unable to read public key from file: open foo: no such file or directory"
if runtime.GOOS == "windows" {
expectedError = "unable to read public key from file: open foo: The system cannot find the file specified."
}
assert.Error(t, err, expectedError)
// Call with real file path // Call with real file path
tmpfile, err := ioutil.TempFile("", "pemfile") tmpfile, err := ioutil.TempFile("", "pemfile")
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -1,6 +1,8 @@
package loader package loader
import ( import (
"fmt"
"path/filepath"
"time" "time"
"github.com/docker/cli/cli/compose/types" "github.com/docker/cli/cli/compose/types"
@ -313,10 +315,10 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
{Target: "/var/lib/mysql", Type: "volume"}, {Target: "/var/lib/mysql", Type: "volume"},
{Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"}, {Source: "/opt/data", Target: "/var/lib/mysql", Type: "bind"},
{Source: workingDir, Target: "/code", Type: "bind"}, {Source: workingDir, Target: "/code", Type: "bind"},
{Source: workingDir + "/static", Target: "/var/www/html", Type: "bind"}, {Source: filepath.Join(workingDir, "static"), Target: "/var/www/html", Type: "bind"},
{Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true}, {Source: homeDir + "/configs", Target: "/etc/configs/", Type: "bind", ReadOnly: true},
{Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"}, {Source: "datavolume", Target: "/var/lib/mysql", Type: "volume"},
{Source: workingDir + "/opt", Target: "/opt", Consistency: "cached", Type: "bind"}, {Source: filepath.Join(workingDir, "opt"), Target: "/opt", Consistency: "cached", Type: "bind"},
{Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{ {Target: "/opt", Type: "tmpfs", Tmpfs: &types.ServiceVolumeTmpfs{
Size: int64(10000), Size: int64(10000),
}}, }},
@ -389,3 +391,313 @@ func volumes() map[string]types.VolumeConfig {
}, },
} }
} }
func fullExampleYAML(workingDir string) string {
return fmt.Sprintf(`version: "3.6"
services:
foo:
build:
context: ./dir
dockerfile: Dockerfile
args:
foo: bar
labels:
FOO: BAR
cache_from:
- foo
- bar
network: foo
target: foo
cap_add:
- ALL
cap_drop:
- NET_ADMIN
- SYS_ADMIN
cgroup_parent: m-executor-abcd
command:
- bundle
- exec
- thin
- -p
- "3000"
container_name: my-web-container
depends_on:
- db
- redis
deploy:
mode: replicated
replicas: 6
labels:
FOO: BAR
update_config:
parallelism: 3
delay: 10s
failure_action: continue
monitor: 1m0s
max_failure_ratio: 0.3
order: start-first
resources:
limits:
cpus: "0.001"
memory: "52428800"
reservations:
cpus: "0.0001"
memory: "20971520"
generic_resources:
- discrete_resource_spec:
kind: gpu
value: 2
- discrete_resource_spec:
kind: ssd
value: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 2m0s
placement:
constraints:
- node=foo
preferences:
- spread: node.labels.az
endpoint_mode: dnsrr
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
dns:
- 8.8.8.8
- 9.9.9.9
dns_search:
- dc1.example.com
- dc2.example.com
domainname: foo.com
entrypoint:
- /code/entrypoint.sh
- -p
- "3000"
environment:
BAR: bar_from_env_file_2
BAZ: baz_from_service_def
FOO: foo_from_env_file
QUX: qux_from_environment
env_file:
- ./example1.env
- ./example2.env
expose:
- "3000"
- "8000"
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgresql
extra_hosts:
- somehost:162.242.195.82
- otherhost:50.31.209.229
hostname: foo
healthcheck:
test:
- CMD-SHELL
- echo "hello world"
timeout: 1s
interval: 10s
retries: 5
start_period: 15s
image: redis
ipc: host
labels:
com.example.description: Accounting webapp
com.example.empty-label: ""
com.example.number: "42"
links:
- db
- db:database
- redis
logging:
driver: syslog
options:
syslog-address: tcp://192.168.0.42:123
mac_address: 02:42:ac:11:65:43
network_mode: container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b
networks:
other-network:
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10
other-other-network: null
some-network:
aliases:
- alias1
- alias3
pid: host
ports:
- mode: ingress
target: 3000
protocol: tcp
- mode: ingress
target: 3001
protocol: tcp
- mode: ingress
target: 3002
protocol: tcp
- mode: ingress
target: 3003
protocol: tcp
- mode: ingress
target: 3004
protocol: tcp
- mode: ingress
target: 3005
protocol: tcp
- mode: ingress
target: 8000
published: 8000
protocol: tcp
- mode: ingress
target: 8080
published: 9090
protocol: tcp
- mode: ingress
target: 8081
published: 9091
protocol: tcp
- mode: ingress
target: 22
published: 49100
protocol: tcp
- mode: ingress
target: 8001
published: 8001
protocol: tcp
- mode: ingress
target: 5000
published: 5000
protocol: tcp
- mode: ingress
target: 5001
published: 5001
protocol: tcp
- mode: ingress
target: 5002
published: 5002
protocol: tcp
- mode: ingress
target: 5003
published: 5003
protocol: tcp
- mode: ingress
target: 5004
published: 5004
protocol: tcp
- mode: ingress
target: 5005
published: 5005
protocol: tcp
- mode: ingress
target: 5006
published: 5006
protocol: tcp
- mode: ingress
target: 5007
published: 5007
protocol: tcp
- mode: ingress
target: 5008
published: 5008
protocol: tcp
- mode: ingress
target: 5009
published: 5009
protocol: tcp
- mode: ingress
target: 5010
published: 5010
protocol: tcp
privileged: true
read_only: true
restart: always
security_opt:
- label=level:s0:c100,c200
- label=type:svirt_apache_t
stdin_open: true
stop_grace_period: 20s
stop_signal: SIGUSR1
tmpfs:
- /run
- /tmp
tty: true
ulimits:
nofile:
soft: 20000
hard: 40000
nproc: 65535
user: someone
volumes:
- type: volume
target: /var/lib/mysql
- type: bind
source: /opt/data
target: /var/lib/mysql
- type: bind
source: /foo
target: /code
- type: bind
source: %s
target: /var/www/html
- type: bind
source: /bar/configs
target: /etc/configs/
read_only: true
- type: volume
source: datavolume
target: /var/lib/mysql
- type: bind
source: %s
target: /opt
consistency: cached
- type: tmpfs
target: /opt
tmpfs:
size: 10000
working_dir: /code
networks:
external-network:
name: external-network
external: true
other-external-network:
name: my-cool-network
external: true
other-network:
driver: overlay
driver_opts:
baz: "1"
foo: bar
ipam:
driver: overlay
config:
- subnet: 172.16.238.0/24
- subnet: 2001:3984:3989::/64
some-network: {}
volumes:
another-volume:
name: user_specified_name
driver: vsphere
driver_opts:
baz: "1"
foo: bar
external-volume:
name: external-volume
external: true
external-volume3:
name: this-is-volume3
external: true
other-external-volume:
name: my-cool-volume
external: true
other-volume:
driver: flocker
driver_opts:
baz: "1"
foo: bar
some-volume: {}
secrets: {}
configs: {}
`, filepath.Join(workingDir, "static"), filepath.Join(workingDir, "opt"))
}

View File

@ -9,314 +9,10 @@ import (
) )
func TestMarshallConfig(t *testing.T) { func TestMarshallConfig(t *testing.T) {
cfg := fullExampleConfig("/foo", "/bar") workingDir := "/foo"
expected := `version: "3.6" homeDir := "/bar"
services: cfg := fullExampleConfig(workingDir, homeDir)
foo: expected := fullExampleYAML(workingDir)
build:
context: ./dir
dockerfile: Dockerfile
args:
foo: bar
labels:
FOO: BAR
cache_from:
- foo
- bar
network: foo
target: foo
cap_add:
- ALL
cap_drop:
- NET_ADMIN
- SYS_ADMIN
cgroup_parent: m-executor-abcd
command:
- bundle
- exec
- thin
- -p
- "3000"
container_name: my-web-container
depends_on:
- db
- redis
deploy:
mode: replicated
replicas: 6
labels:
FOO: BAR
update_config:
parallelism: 3
delay: 10s
failure_action: continue
monitor: 1m0s
max_failure_ratio: 0.3
order: start-first
resources:
limits:
cpus: "0.001"
memory: "52428800"
reservations:
cpus: "0.0001"
memory: "20971520"
generic_resources:
- discrete_resource_spec:
kind: gpu
value: 2
- discrete_resource_spec:
kind: ssd
value: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 2m0s
placement:
constraints:
- node=foo
preferences:
- spread: node.labels.az
endpoint_mode: dnsrr
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
dns:
- 8.8.8.8
- 9.9.9.9
dns_search:
- dc1.example.com
- dc2.example.com
domainname: foo.com
entrypoint:
- /code/entrypoint.sh
- -p
- "3000"
environment:
BAR: bar_from_env_file_2
BAZ: baz_from_service_def
FOO: foo_from_env_file
QUX: qux_from_environment
env_file:
- ./example1.env
- ./example2.env
expose:
- "3000"
- "8000"
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgresql
extra_hosts:
- somehost:162.242.195.82
- otherhost:50.31.209.229
hostname: foo
healthcheck:
test:
- CMD-SHELL
- echo "hello world"
timeout: 1s
interval: 10s
retries: 5
start_period: 15s
image: redis
ipc: host
labels:
com.example.description: Accounting webapp
com.example.empty-label: ""
com.example.number: "42"
links:
- db
- db:database
- redis
logging:
driver: syslog
options:
syslog-address: tcp://192.168.0.42:123
mac_address: 02:42:ac:11:65:43
network_mode: container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b
networks:
other-network:
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10
other-other-network: null
some-network:
aliases:
- alias1
- alias3
pid: host
ports:
- mode: ingress
target: 3000
protocol: tcp
- mode: ingress
target: 3001
protocol: tcp
- mode: ingress
target: 3002
protocol: tcp
- mode: ingress
target: 3003
protocol: tcp
- mode: ingress
target: 3004
protocol: tcp
- mode: ingress
target: 3005
protocol: tcp
- mode: ingress
target: 8000
published: 8000
protocol: tcp
- mode: ingress
target: 8080
published: 9090
protocol: tcp
- mode: ingress
target: 8081
published: 9091
protocol: tcp
- mode: ingress
target: 22
published: 49100
protocol: tcp
- mode: ingress
target: 8001
published: 8001
protocol: tcp
- mode: ingress
target: 5000
published: 5000
protocol: tcp
- mode: ingress
target: 5001
published: 5001
protocol: tcp
- mode: ingress
target: 5002
published: 5002
protocol: tcp
- mode: ingress
target: 5003
published: 5003
protocol: tcp
- mode: ingress
target: 5004
published: 5004
protocol: tcp
- mode: ingress
target: 5005
published: 5005
protocol: tcp
- mode: ingress
target: 5006
published: 5006
protocol: tcp
- mode: ingress
target: 5007
published: 5007
protocol: tcp
- mode: ingress
target: 5008
published: 5008
protocol: tcp
- mode: ingress
target: 5009
published: 5009
protocol: tcp
- mode: ingress
target: 5010
published: 5010
protocol: tcp
privileged: true
read_only: true
restart: always
security_opt:
- label=level:s0:c100,c200
- label=type:svirt_apache_t
stdin_open: true
stop_grace_period: 20s
stop_signal: SIGUSR1
tmpfs:
- /run
- /tmp
tty: true
ulimits:
nofile:
soft: 20000
hard: 40000
nproc: 65535
user: someone
volumes:
- type: volume
target: /var/lib/mysql
- type: bind
source: /opt/data
target: /var/lib/mysql
- type: bind
source: /foo
target: /code
- type: bind
source: /foo/static
target: /var/www/html
- type: bind
source: /bar/configs
target: /etc/configs/
read_only: true
- type: volume
source: datavolume
target: /var/lib/mysql
- type: bind
source: /foo/opt
target: /opt
consistency: cached
- type: tmpfs
target: /opt
tmpfs:
size: 10000
working_dir: /code
networks:
external-network:
name: external-network
external: true
other-external-network:
name: my-cool-network
external: true
other-network:
driver: overlay
driver_opts:
baz: "1"
foo: bar
ipam:
driver: overlay
config:
- subnet: 172.16.238.0/24
- subnet: 2001:3984:3989::/64
some-network: {}
volumes:
another-volume:
name: user_specified_name
driver: vsphere
driver_opts:
baz: "1"
foo: bar
external-volume:
name: external-volume
external: true
external-volume3:
name: this-is-volume3
external: true
other-external-volume:
name: my-cool-volume
external: true
other-volume:
driver: flocker
driver_opts:
baz: "1"
foo: bar
some-volume: {}
secrets: {}
configs: {}
`
actual, err := yaml.Marshal(cfg) actual, err := yaml.Marshal(cfg)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -155,7 +155,7 @@ func pullManifestList(ctx context.Context, ref reference.Named, repo distributio
} }
v, ok := manifest.(*schema2.DeserializedManifest) v, ok := manifest.(*schema2.DeserializedManifest)
if !ok { if !ok {
return nil, fmt.Errorf("unsupported manifest format: %s", v) return nil, fmt.Errorf("unsupported manifest format: %v", v)
} }
manifestRef, err := reference.WithDigest(ref, manifestDescriptor.Digest) manifestRef, err := reference.WithDigest(ref, manifestDescriptor.Digest)

172
scripts/make.ps1 Normal file
View File

@ -0,0 +1,172 @@
<#
.NOTES
Summary: Windows native build script.
It does however provided the minimum necessary to support parts of local Windows
development and Windows to Windows CI.
Usage Examples (run from repo root):
"scripts/make.ps1 -Client" to build docker.exe client 64-bit binary (remote repo)
"scripts/make.ps1 -TestUnit" to run unit tests
"scripts/make.ps1 -Daemon -TestUnit" to build the daemon and run unit tests
"scripts/make.ps1 -All" to run everything this script knows about that can run in a container
"scripts/make.ps1" to build the daemon binary (same as -Daemon)
"scripts/make.ps1 -Binary" shortcut to -Client and -Daemon
.PARAMETER Binary
Builds the client and daemon binaries. A convenient shortcut to `make.ps1 -Client -Daemon`.
.PARAMETER Race
Use -race in go build and go test.
.PARAMETER Noisy
Use -v in go build.
.PARAMETER ForceBuildAll
Use -a in go build.
.PARAMETER NoOpt
Use -gcflags -N -l in go build to disable optimisation (can aide debugging).
.PARAMETER CommitSuffix
Adds a custom string to be appended to the commit ID (spaces are stripped).
.PARAMETER TestUnit
Runs unit tests.
.PARAMETER All
Runs everything this script knows about that can run in a container.
TODO
- Unify the head commit
- Add golint and other checks (swagger maybe?)
#>
param(
[Parameter(Mandatory=$False)][switch]$Binary,
[Parameter(Mandatory=$False)][switch]$Race,
[Parameter(Mandatory=$False)][switch]$Noisy,
[Parameter(Mandatory=$False)][switch]$ForceBuildAll,
[Parameter(Mandatory=$False)][switch]$NoOpt,
[Parameter(Mandatory=$False)][switch]$TestUnit,
[Parameter(Mandatory=$False)][switch]$All
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$pushed=$False # To restore the directory if we have temporarily pushed to one.
# Build a binary (client or daemon)
Function Execute-Build($additionalBuildTags, $directory) {
# Generate the build flags
$buildTags = "autogen"
if ($Noisy) { $verboseParm=" -v" }
if ($Race) { Write-Warning "Using race detector"; $raceParm=" -race"}
if ($ForceBuildAll) { $allParm=" -a" }
if ($NoOpt) { $optParm=" -gcflags "+""""+"-N -l"+"""" }
if ($additionalBuildTags -ne "") { $buildTags += $(" " + $additionalBuildTags) }
# Do the go build in the appropriate directory
# Note -linkmode=internal is required to be able to debug on Windows.
# https://github.com/golang/go/issues/14319#issuecomment-189576638
Write-Host "INFO: Building..."
Push-Location $root\cmd\$directory; $global:pushed=$True
$buildCommand = "go build" + `
$raceParm + `
$verboseParm + `
$allParm + `
$optParm + `
" -tags """ + $buildTags + """" + `
" -ldflags """ + "-linkmode=internal" + """" + `
" -o $root\build\"+$directory+".exe"
Invoke-Expression $buildCommand
if ($LASTEXITCODE -ne 0) { Throw "Failed to compile" }
Pop-Location; $global:pushed=$False
}
# Run the unit tests
Function Run-UnitTests() {
Write-Host "INFO: Running unit tests..."
$testPath="./..."
$goListCommand = "go list -e -f '{{if ne .Name """ + '\"github.com/docker/cli\"' + """}}{{.ImportPath}}{{end}}' $testPath"
$pkgList = $(Invoke-Expression $goListCommand)
if ($LASTEXITCODE -ne 0) { Throw "go list for unit tests failed" }
$pkgList = $pkgList | Select-String -Pattern "github.com/docker/cli"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/cli/vendor"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/cli/man"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/cli/e2e"
$pkgList = $pkgList -replace "`r`n", " "
$goTestCommand = "go test" + $raceParm + " -cover -ldflags -w -tags """ + "autogen" + """ -a """ + "-test.timeout=10m" + """ $pkgList"
Invoke-Expression $goTestCommand
if ($LASTEXITCODE -ne 0) { Throw "Unit tests failed" }
}
# Start of main code.
Try {
Write-Host -ForegroundColor Cyan "INFO: make.ps1 starting at $(Get-Date)"
# Get to the root of the repo
$root = $(Split-Path $MyInvocation.MyCommand.Definition -Parent | Split-Path -Parent)
Push-Location $root
# Handle the "-All" shortcut to turn on all things we can handle.
# Note we expressly only include the items which can run in a container - the validations tests cannot
# as they require the .git directory which is excluded from the image by .dockerignore
if ($All) { $Client=$True; $TestUnit=$True }
# Handle the "-Binary" shortcut to build both client and daemon.
if ($Binary) { $Client = $True; }
# Verify git is installed
if ($(Get-Command git -ErrorAction SilentlyContinue) -eq $nil) { Throw "Git does not appear to be installed" }
# Verify go is installed
if ($(Get-Command go -ErrorAction SilentlyContinue) -eq $nil) { Throw "GoLang does not appear to be installed" }
# Build the binaries
if ($Client) {
# Create the build directory if it doesn't exist
if (-not (Test-Path ".\build")) { New-Item ".\build" -ItemType Directory | Out-Null }
# Perform the actual build
Execute-Build "" "docker"
}
# Run unit tests
if ($TestUnit) { Run-UnitTests }
# Gratuitous ASCII art.
if ($Client) {
Write-Host
Write-Host -ForegroundColor Green " ________ ____ __."
Write-Host -ForegroundColor Green " \_____ \ `| `|/ _`|"
Write-Host -ForegroundColor Green " / `| \`| `<"
Write-Host -ForegroundColor Green " / `| \ `| \"
Write-Host -ForegroundColor Green " \_______ /____`|__ \"
Write-Host -ForegroundColor Green " \/ \/"
Write-Host
}
}
Catch [Exception] {
Write-Host -ForegroundColor Red ("`nERROR: make.ps1 failed:`n$_")
# More gratuitous ASCII art.
Write-Host
Write-Host -ForegroundColor Red "___________ .__.__ .___"
Write-Host -ForegroundColor Red "\_ _____/____ `|__`| `| ____ __`| _/"
Write-Host -ForegroundColor Red " `| __) \__ \ `| `| `| _/ __ \ / __ `| "
Write-Host -ForegroundColor Red " `| \ / __ \`| `| `|_\ ___// /_/ `| "
Write-Host -ForegroundColor Red " \___ / (____ /__`|____/\___ `>____ `| "
Write-Host -ForegroundColor Red " \/ \/ \/ \/ "
Write-Host
Throw $_
}
Finally {
Pop-Location # As we pushed to the root of the repo as the very first thing
if ($global:pushed) { Pop-Location }
Write-Host -ForegroundColor Cyan "INFO: make.ps1 ended at $(Get-Date)"
}

View File

@ -2,4 +2,4 @@
set -eo pipefail set -eo pipefail
shellcheck contrib/completion/bash/docker shellcheck contrib/completion/bash/docker
find scripts/ -type f | grep -v scripts/winresources | xargs shellcheck find scripts/ -type f | grep -v scripts/winresources | grep -v '.*.ps1' | xargs shellcheck