From facb22573d0d215c511b840db6417aebd2b1122e Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Tue, 27 Feb 2018 14:11:32 +0100 Subject: [PATCH 1/3] Add appveyor setup to build and unit test Adds a `make.ps1` powershell script to make it easy to compile and test. ``` .\scripts\make.ps1 -Binary INFO: make.ps1 starting at 03/01/2018 14:37:28 INFO: Building... ________ ____ __. \_____ \ | |/ _| / | \| < / | \ | \ \_______ /____|__ \ \/ \/ INFO: make.ps1 ended at 03/01/2018 14:37:30 .\scripts\make.ps1 -TestUnit ``` The next step is to run e2e tests on windows too. Signed-off-by: Vincent Demeester --- appveyor.yml | 23 +++++ scripts/make.ps1 | 197 ++++++++++++++++++++++++++++++++++++ scripts/validate/shellcheck | 10 +- 3 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 appveyor.yml create mode 100644 scripts/make.ps1 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..262021d8ab --- /dev/null +++ b/appveyor.yml @@ -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 \ No newline at end of file diff --git a/scripts/make.ps1 b/scripts/make.ps1 new file mode 100644 index 0000000000..dde83f8025 --- /dev/null +++ b/scripts/make.ps1 @@ -0,0 +1,197 @@ +<# +.NOTES + Author: @vdemeester + + 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): + "hack\make.ps1 -Client" to build docker.exe client 64-bit binary (remote repo) + "hack\make.ps1 -TestUnit" to run unit tests + "hack\make.ps1 -Daemon -TestUnit" to build the daemon and run unit tests + "hack\make.ps1 -All" to run everything this script knows about that can run in a container + "hack\make.ps1" to build the daemon binary (same as -Daemon) + "hack\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. + +# Utility function to get the commit ID of the repository +Function Get-GitCommit() { + if (-not (Test-Path ".\.git")) { + # If we don't have a .git directory, but we do have the environment + # variable DOCKER_GITCOMMIT set, that can override it. + if ($env:DOCKER_GITCOMMIT.Length -eq 0) { + Throw ".git directory missing and DOCKER_GITCOMMIT environment variable not specified." + } + Write-Host "INFO: Git commit ($env:DOCKER_GITCOMMIT) assumed from DOCKER_GITCOMMIT environment variable" + return $env:DOCKER_GITCOMMIT + } + $gitCommit=$(git rev-parse --short HEAD) + if ($(git status --porcelain --untracked-files=no).Length -ne 0) { + $gitCommit="$gitCommit-unsupported" + Write-Host "" + Write-Warning "This version is unsupported because there are uncommitted file(s)." + Write-Warning "Either commit these changes, or add them to .gitignore." + git status --porcelain --untracked-files=no | Write-Warning + Write-Host "" + } + return $gitCommit +} + +# 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)" +} diff --git a/scripts/validate/shellcheck b/scripts/validate/shellcheck index f7ce7024d3..8b0df25b73 100755 --- a/scripts/validate/shellcheck +++ b/scripts/validate/shellcheck @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -eo pipefail - -shellcheck contrib/completion/bash/docker -find scripts/ -type f | grep -v scripts/winresources | xargs shellcheck +#!/usr/bin/env bash +set -eo pipefail + +shellcheck contrib/completion/bash/docker +find scripts/ -type f | grep -v scripts/winresources | grep -v '*.ps1' | xargs shellcheck From 0cf2e6353a88a12b78da72db6a7e7c7d049d3ed8 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Tue, 27 Feb 2018 16:54:36 +0100 Subject: [PATCH 2/3] Fixes some unit tests to be able to run them on windows Some of them are skipped for now (because the feature is not supported or needs more work), some of them are fixed. Signed-off-by: Vincent Demeester --- cli/command/cli_test.go | 4 + cli/command/container/cp_test.go | 7 +- cli/command/formatter/history_test.go | 6 +- cli/command/image/build_linux_test.go | 54 +++ cli/command/image/build_test.go | 38 --- cli/command/plugin/create_test.go | 15 +- .../stack/swarm/deploy_composefile_test.go | 11 +- cli/command/trust/key_generate_test.go | 2 +- cli/command/trust/key_load_test.go | 11 +- cli/command/trust/sign_test.go | 3 + cli/command/trust/signer_add_test.go | 13 +- cli/compose/loader/full-struct_test.go | 316 +++++++++++++++++- cli/compose/loader/types_test.go | 312 +---------------- cli/registry/client/fetcher.go | 2 +- scripts/validate/shellcheck | 10 +- 15 files changed, 435 insertions(+), 369 deletions(-) create mode 100644 cli/command/image/build_linux_test.go diff --git a/cli/command/cli_test.go b/cli/command/cli_test.go index 48a87d1bfb..432e653fdc 100644 --- a/cli/command/cli_test.go +++ b/cli/command/cli_test.go @@ -3,6 +3,7 @@ package command import ( "crypto/x509" "os" + "runtime" "testing" cliconfig "github.com/docker/cli/cli/config" @@ -20,6 +21,9 @@ import ( func TestNewAPIClientFromFlags(t *testing.T) { host := "unix://path" + if runtime.GOOS == "windows" { + host = "npipe://./" + } opts := &flags.CommonOptions{Hosts: []string{host}} configFile := &configfile.ConfigFile{ HTTPHeaders: map[string]string{ diff --git a/cli/command/container/cp_test.go b/cli/command/container/cp_test.go index 78fb3e237f..7d706f354c 100644 --- a/cli/command/container/cp_test.go +++ b/cli/command/container/cp_test.go @@ -121,7 +121,12 @@ func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) { } cli := test.NewFakeCli(&fakeClient{}) 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) { diff --git a/cli/command/formatter/history_test.go b/cli/command/formatter/history_test.go index d8e5dde1f6..77423a8010 100644 --- a/cli/command/formatter/history_test.go +++ b/cli/command/formatter/history_test.go @@ -1,13 +1,12 @@ package formatter import ( + "bytes" "strconv" "strings" "testing" "time" - "bytes" - "github.com/docker/docker/api/types/image" "github.com/docker/docker/pkg/stringid" "github.com/gotestyourself/gotestyourself/assert" @@ -51,6 +50,7 @@ func TestHistoryContext_ID(t *testing.T) { } func TestHistoryContext_CreatedSince(t *testing.T) { + dateStr := "2009-11-10T23:00:00Z" var ctx historyContext 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()}, trunc: false, human: false, - }, "2009-11-10T23:00:00Z", ctx.CreatedSince, + }, dateStr, ctx.CreatedSince, }, } diff --git a/cli/command/image/build_linux_test.go b/cli/command/image/build_linux_test.go new file mode 100644 index 0000000000..59b2871b4e --- /dev/null +++ b/cli/command/image/build_linux_test.go @@ -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)) + } +} diff --git a/cli/command/image/build_test.go b/cli/command/image/build_test.go index a178a93cea..31f53fa0d1 100644 --- a/cli/command/image/build_test.go +++ b/cli/command/image/build_test.go @@ -6,9 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" - "runtime" "sort" - "syscall" "testing" "github.com/docker/cli/cli/command" @@ -18,45 +16,9 @@ import ( "github.com/gotestyourself/gotestyourself/assert" is "github.com/gotestyourself/gotestyourself/assert/cmp" "github.com/gotestyourself/gotestyourself/fs" - "github.com/gotestyourself/gotestyourself/skip" "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) { dest, err := ioutil.TempDir("", "test-build-compress-dest") assert.NilError(t, err) diff --git a/cli/command/plugin/create_test.go b/cli/command/plugin/create_test.go index 87e17d3793..41191cab35 100644 --- a/cli/command/plugin/create_test.go +++ b/cli/command/plugin/create_test.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "io/ioutil" + "runtime" "testing" "github.com/docker/cli/internal/test" @@ -14,7 +15,10 @@ import ( ) 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 { args []string expectedError string @@ -29,7 +33,7 @@ func TestCreateErrors(t *testing.T) { }, { 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.SetArgs([]string{"plugin-foo", tmpDir.Path()}) 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) { diff --git a/cli/command/stack/swarm/deploy_composefile_test.go b/cli/command/stack/swarm/deploy_composefile_test.go index 91c318cd63..2903fd3c42 100644 --- a/cli/command/stack/swarm/deploy_composefile_test.go +++ b/cli/command/stack/swarm/deploy_composefile_test.go @@ -33,10 +33,13 @@ func TestValidateExternalNetworks(t *testing.T) { inspectError: errors.New("Unexpected"), expectedMsg: "Unexpected", }, - { - inspectError: errors.New("host net does not exist on swarm classic"), - network: "host", - }, + // 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"), + network: "host", + }, + */ { network: "user", expectedMsg: "is not in the right scope", diff --git a/cli/command/trust/key_generate_test.go b/cli/command/trust/key_generate_test.go index bad5164941..6e26f98d1f 100644 --- a/cli/command/trust/key_generate_test.go +++ b/cli/command/trust/key_generate_test.go @@ -127,7 +127,7 @@ func TestValidateKeyArgs(t *testing.T) { assert.NilError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms)) 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/") assert.Error(t, err, "public key path does not exist: \"/random/dir/\"") diff --git a/cli/command/trust/key_load_test.go b/cli/command/trust/key_load_test.go index b24f528ef0..c4da320a59 100644 --- a/cli/command/trust/key_load_test.go +++ b/cli/command/trust/key_load_test.go @@ -6,12 +6,14 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "testing" "github.com/docker/cli/cli/config" "github.com/docker/cli/internal/test" "github.com/gotestyourself/gotestyourself/assert" is "github.com/gotestyourself/gotestyourself/assert/cmp" + "github.com/gotestyourself/gotestyourself/skip" "github.com/theupdateframework/notary" "github.com/theupdateframework/notary/passphrase" "github.com/theupdateframework/notary/storage" @@ -20,6 +22,10 @@ import ( ) 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 { name string args []string @@ -40,7 +46,7 @@ func TestTrustKeyLoadErrors(t *testing.T) { { name: "not-a-key", 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", }, { @@ -109,6 +115,7 @@ var testKeys = map[string][]byte{ } func TestLoadKeyFromPath(t *testing.T) { + skip.If(t, runtime.GOOS == "windows") for keyID, keyBytes := range testKeys { t.Run(fmt.Sprintf("load-key-id-%s-from-path", keyID), func(t *testing.T) { testLoadKeyFromPath(t, keyID, keyBytes) @@ -163,6 +170,7 @@ func testLoadKeyFromPath(t *testing.T, privKeyID string, privKeyFixture []byte) } func TestLoadKeyTooPermissive(t *testing.T) { + skip.If(t, runtime.GOOS == "windows") for keyID, keyBytes := range testKeys { t.Run(fmt.Sprintf("load-key-id-%s-too-permissive", keyID), func(t *testing.T) { testLoadKeyTooPermissive(t, keyBytes) @@ -219,6 +227,7 @@ H3nzy2O6Q/ct4BjOBKa+WCdRtPo78bA+C/7t81ADQO8Jqaj59W50rwoqDQ== -----END PUBLIC KEY-----`) func TestLoadPubKeyFailure(t *testing.T) { + skip.If(t, runtime.GOOS == "windows") pubKeyDir, err := ioutil.TempDir("", "key-load-test-pubkey-") assert.NilError(t, err) defer os.RemoveAll(pubKeyDir) diff --git a/cli/command/trust/sign_test.go b/cli/command/trust/sign_test.go index 523b2792e4..002cbd5fe8 100644 --- a/cli/command/trust/sign_test.go +++ b/cli/command/trust/sign_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "io/ioutil" "os" + "runtime" "testing" "github.com/docker/cli/cli/config" @@ -12,6 +13,7 @@ import ( "github.com/docker/cli/internal/test" "github.com/gotestyourself/gotestyourself/assert" is "github.com/gotestyourself/gotestyourself/assert/cmp" + "github.com/gotestyourself/gotestyourself/skip" "github.com/theupdateframework/notary" "github.com/theupdateframework/notary/client" "github.com/theupdateframework/notary/client/changelist" @@ -127,6 +129,7 @@ func TestGetOrGenerateNotaryKey(t *testing.T) { } func TestAddStageSigners(t *testing.T) { + skip.If(t, runtime.GOOS == "windows", "FIXME: not supported currently") tmpDir, err := ioutil.TempDir("", "notary-test-") assert.NilError(t, err) defer os.RemoveAll(tmpDir) diff --git a/cli/command/trust/signer_add_test.go b/cli/command/trust/signer_add_test.go index d2e1e21481..0f0c404d24 100644 --- a/cli/command/trust/signer_add_test.go +++ b/cli/command/trust/signer_add_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "testing" "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.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) { @@ -127,7 +132,11 @@ func TestSignerAddCommandInvalidRepoName(t *testing.T) { func TestIngestPublicKeys(t *testing.T) { // Call with a bad path _, 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 tmpfile, err := ioutil.TempFile("", "pemfile") assert.NilError(t, err) diff --git a/cli/compose/loader/full-struct_test.go b/cli/compose/loader/full-struct_test.go index 3f2a587bce..b9afa7ef65 100644 --- a/cli/compose/loader/full-struct_test.go +++ b/cli/compose/loader/full-struct_test.go @@ -1,6 +1,8 @@ package loader import ( + "fmt" + "path/filepath" "time" "github.com/docker/cli/cli/compose/types" @@ -313,10 +315,10 @@ func services(workingDir, homeDir string) []types.ServiceConfig { {Target: "/var/lib/mysql", Type: "volume"}, {Source: "/opt/data", Target: "/var/lib/mysql", 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: "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{ 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")) +} diff --git a/cli/compose/loader/types_test.go b/cli/compose/loader/types_test.go index b324c8e580..75ea835bd7 100644 --- a/cli/compose/loader/types_test.go +++ b/cli/compose/loader/types_test.go @@ -9,314 +9,10 @@ import ( ) func TestMarshallConfig(t *testing.T) { - cfg := fullExampleConfig("/foo", "/bar") - expected := `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: /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: {} -` + workingDir := "/foo" + homeDir := "/bar" + cfg := fullExampleConfig(workingDir, homeDir) + expected := fullExampleYAML(workingDir) actual, err := yaml.Marshal(cfg) assert.NilError(t, err) diff --git a/cli/registry/client/fetcher.go b/cli/registry/client/fetcher.go index 1e748f255d..796bc01eb1 100644 --- a/cli/registry/client/fetcher.go +++ b/cli/registry/client/fetcher.go @@ -155,7 +155,7 @@ func pullManifestList(ctx context.Context, ref reference.Named, repo distributio } v, ok := manifest.(*schema2.DeserializedManifest) 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) diff --git a/scripts/validate/shellcheck b/scripts/validate/shellcheck index 8b0df25b73..63cedf137b 100755 --- a/scripts/validate/shellcheck +++ b/scripts/validate/shellcheck @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -eo pipefail - -shellcheck contrib/completion/bash/docker -find scripts/ -type f | grep -v scripts/winresources | grep -v '*.ps1' | xargs shellcheck +#!/usr/bin/env bash +set -eo pipefail + +shellcheck contrib/completion/bash/docker +find scripts/ -type f | grep -v scripts/winresources | grep -v '.*.ps1' | xargs shellcheck From 10baa756b264778ae0c64ba058c8aeea733ed6fa Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 7 Mar 2018 18:13:48 +0100 Subject: [PATCH 3/3] Remove unused powershell function Signed-off-by: Vincent Demeester --- scripts/make.ps1 | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/scripts/make.ps1 b/scripts/make.ps1 index dde83f8025..bb875b59cd 100644 --- a/scripts/make.ps1 +++ b/scripts/make.ps1 @@ -1,19 +1,17 @@ <# .NOTES - Author: @vdemeester - 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): - "hack\make.ps1 -Client" to build docker.exe client 64-bit binary (remote repo) - "hack\make.ps1 -TestUnit" to run unit tests - "hack\make.ps1 -Daemon -TestUnit" to build the daemon and run unit tests - "hack\make.ps1 -All" to run everything this script knows about that can run in a container - "hack\make.ps1" to build the daemon binary (same as -Daemon) - "hack\make.ps1 -Binary" shortcut to -Client and -Daemon + "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`. @@ -61,29 +59,6 @@ $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" $pushed=$False # To restore the directory if we have temporarily pushed to one. -# Utility function to get the commit ID of the repository -Function Get-GitCommit() { - if (-not (Test-Path ".\.git")) { - # If we don't have a .git directory, but we do have the environment - # variable DOCKER_GITCOMMIT set, that can override it. - if ($env:DOCKER_GITCOMMIT.Length -eq 0) { - Throw ".git directory missing and DOCKER_GITCOMMIT environment variable not specified." - } - Write-Host "INFO: Git commit ($env:DOCKER_GITCOMMIT) assumed from DOCKER_GITCOMMIT environment variable" - return $env:DOCKER_GITCOMMIT - } - $gitCommit=$(git rev-parse --short HEAD) - if ($(git status --porcelain --untracked-files=no).Length -ne 0) { - $gitCommit="$gitCommit-unsupported" - Write-Host "" - Write-Warning "This version is unsupported because there are uncommitted file(s)." - Write-Warning "Either commit these changes, or add them to .gitignore." - git status --porcelain --untracked-files=no | Write-Warning - Write-Host "" - } - return $gitCommit -} - # Build a binary (client or daemon) Function Execute-Build($additionalBuildTags, $directory) { # Generate the build flags