Compare commits

...

59 Commits

Author SHA1 Message Date
piotrostr f985c12182
Merge b1c7307ff1 into 9c01d924fb 2024-11-07 00:05:13 +01:00
Sebastiaan van Stijn 9c01d924fb
Merge pull request #5595 from dvdksn/docs-redis-example-tags
docs: update example redis tags from 3.0.x to 7.4.x
2024-11-06 15:52:12 +01:00
Sebastiaan van Stijn 8c22315e31
Merge pull request #5596 from laurazard/update-jwt-dep-v4
deps: update `go-jose/go-jose` to `v4`
2024-11-05 15:29:00 +01:00
Laura Brehm 13754f6776
deps: update `go-jose/go-jose` to `v4`
See: https://github.com/go-jose/go-jose

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-11-05 14:12:16 +00:00
Sebastiaan van Stijn 9eb7b52189
Merge pull request #5594 from thaJeztah/fix_golangci_go_version
golangci-lint: set go version to prevent fallback to go1.17, and fix copyloopvar linting issues
2024-11-05 11:24:44 +01:00
David Karlsson 172f340112 docs: update example redis tags from 3.0.x to 7.4.x
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-11-05 11:20:17 +01:00
Sebastiaan van Stijn 750b8ebcdc
Merge pull request #5590 from thaJeztah/bump_engine_28
vendor: github.com/docker/docker 6ac445c42bad (master, v28.0-dev)
2024-11-05 10:21:26 +01:00
Sebastiaan van Stijn 4a7b04d412
golangci-lint: set go version to prevent fallback to go1.17
GolangCI-lint attempts to deduct the Go version to lint for through the
go version specified in go.mod, which we don't have, and therefore it
falls back to go1.17 semantics:

    level=warning msg="[linters_context] copyloopvar: this linter is disabled because the Go version (1.17) of your project is lower than Go 1.22

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:15:36 +01:00
Sebastiaan van Stijn d77760fe53
cli-plugins/manager: remove redundant capturing of loop vars (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    cli-plugins/manager/cobra.go:55:4: The copy of the 'for' variable "p" can be deleted (Go 1.22+) (copyloopvar)
                p := p
                ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:32 +01:00
Sebastiaan van Stijn 32b40deb46
cli/command/service: remove redundant capturing of loop vars (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    cli/command/service/update.go:1061:3: The copy of the 'for' variable "entry" can be deleted (Go 1.22+) (copyloopvar)
            entry := entry
            ^
    cli/command/service/update.go:1089:4: The copy of the 'for' variable "port" can be deleted (Go 1.22+) (copyloopvar)
                port := port
                ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:32 +01:00
Sebastiaan van Stijn 40833fd296
cli/compose/loader: remove redundant capturing of loop vars (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    cli/compose/loader/merge.go:71:3: The copy of the 'for' variable "overrideService" can be deleted (Go 1.22+) (copyloopvar)
            overrideService := overrideService
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:32 +01:00
Sebastiaan van Stijn 78a7e15032
cli/command/container: remove redundant capturing of loop vars (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    cli/command/container/opts.go:765:3: The copy of the 'for' variable "n" can be deleted (Go 1.22+) (copyloopvar)
            n := n
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:32 +01:00
Sebastiaan van Stijn 4a71ce02e6
cli/command/image: remove redundant capturing of loop vars (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    cli/command/image/tree.go:59:4: The copy of the 'for' variable "im" can be deleted (Go 1.22+) (copyloopvar)
                im := im
                ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:31 +01:00
Sebastiaan van Stijn 7d9ea25564
templates: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:31 +01:00
Sebastiaan van Stijn 046ac9714c
service: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:31 +01:00
Sebastiaan van Stijn 762b5a8df3
opts: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:31 +01:00
Sebastiaan van Stijn 417974cdc3
cmd/docker: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:31 +01:00
Sebastiaan van Stijn bf37e26b33
cli/manifest: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:30 +01:00
Sebastiaan van Stijn 6489a777e5
e2e: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:30 +01:00
Sebastiaan van Stijn 20de861134
cli/config: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:30 +01:00
Sebastiaan van Stijn 1448cecba1
cli/compose: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:30 +01:00
Sebastiaan van Stijn 67458f710d
cli/command: remove redundant capturing of loop vars in tests (copyloopvar)
go1.22 and up now produce a unique variable in loops, tehrefore no longer
requiring to capture the variable manually;

    service/logs/parse_logs_test.go:50:3: The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
            tc := tc
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-05 10:14:30 +01:00
Sebastiaan van Stijn b45477bffa
Merge pull request #5591 from noahsilas/docs-run-exit-code
docs: Correct `run` exit code 126 description
2024-11-04 17:27:25 +01:00
Noah Silas 0c999fe95b docs: Correct `run` exit code 126 description
The command to run inside the container is `/etc`. The semicolon is a
statement terminator, which ends the command `docker run busybox /etc`,
while `echo $?` prints the exit code of that full docker command.

Having this mistake could confuse someone who thinks that `/etc; echo
$?` is all run inside the container, which wouldn't help the reader
understand the exit code of the `docker run` command itself.

Signed-off-by: Noah Silas <noah@hustle.com>
2024-11-04 00:21:33 +00:00
Sebastiaan van Stijn 5f1311ae8d
vendor: github.com/docker/docker 6ac445c42bad (master, v28.0-dev)
full diff: 36a3bd0904...6ac445c42b

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 14:10:15 +01:00
Sebastiaan van Stijn 10c5a57927
vendor: go.opentelemetry.io/contrib/instrumentation/xxx v0.53.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 14:10:09 +01:00
Sebastiaan van Stijn 5e40d288c7
vendor: go.opentelemetry.io/otel v1.28.0
aligning all related packages to v1.28.0 as well

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 14:08:45 +01:00
Sebastiaan van Stijn 9ba73a1a05
vendor: github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0
full diff: https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.16.0...v2.20.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 14:04:41 +01:00
Sebastiaan van Stijn f3cf1b4213
vendor: go.etcd.io/etcd/raft/v3 v3.5.16
no changes in vendored code

full diff: https://github.com/etcd-io/etcd/compare/v3.5.6...v3.5.16

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:54:25 +01:00
Sebastiaan van Stijn cae19e3928
vendor: github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6
no changes in vendored code

full diff: ced1acdcaa...e8a1dd7889

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:46:38 +01:00
Sebastiaan van Stijn 074d1028b5
vendor: update prometheus dependencies
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:44:05 +01:00
Sebastiaan van Stijn 1dbcce2057
vendor: google.golang.org/grpc v1.67.1
full diff:

- https://github.com/grpc/grpc-go/compare/v1.66.2...v1.67.1
- ef581f9131...5fefd90f89

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:39:15 +01:00
Sebastiaan van Stijn 1bba009944
vendor: google.golang.org/protobuf v1.35.1
full diff: https://github.com/protocolbuffers/protobuf-go/compare/v1.34.1...v1.35.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:31:29 +01:00
Sebastiaan van Stijn e3942d46a0
vendor: github.com/klauspost/compress v1.17.11
full diff: https://github.com/klauspost/compress/compare/v1.17.9...v1.17.11

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:28:47 +01:00
Sebastiaan van Stijn 97ff1b7c0a
vendor: github.com/go-logr/logr v1.4.2
full diff: https://github.com/go-logr/logr/compare/v1.4.1...v1.4.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:25:17 +01:00
Sebastiaan van Stijn 4c85feb4dd
vendor: github.com/cenkalti/backoff/v4 v4.3.0
full diff: https://github.com/cenkalti/backoff/compare/v4.2.1...v4.3.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:23:39 +01:00
Sebastiaan van Stijn 3b48a57b04
vendor: github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161
documentation changes only, no changes in vendored code

full diff: d185dfc1b5...306776ec81

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:20:48 +01:00
Sebastiaan van Stijn 36e6c42977
vendor: golang.org/x/net v0.30.0
full diff: https://github.com/golang/net/compare/v0.29.0...v0.30.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:17:57 +01:00
Sebastiaan van Stijn 84bfa52a6c
vendor: golang.org/x/crypto v0.28.0
no changes in vendored code

full diff: https://github.com/golang/crypto/compare/v0.27.0...v0.28.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:16:26 +01:00
Sebastiaan van Stijn 7a94f592ed
vendor: golang.org/x/text v0.19.0
no changes in vendored code

full diff: https://github.com/golang/text/compare/v0.18.0...v0.19.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:14:25 +01:00
Sebastiaan van Stijn ef197f7314
vendor: golang.org/x/term v0.25.0
no changes in vendored code

full diff: https://github.com/golang/term/compare/v0.24.0...v0.25.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:12:59 +01:00
Sebastiaan van Stijn 02b92c699d
vendor: golang.org/x/sys v0.26.0
full diff: https://github.com/golang/sys/compare/v0.25.0...v0.26.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-01 13:11:15 +01:00
Laura Brehm 2995631498
Merge pull request #5586 from Giedriusj1/master 2024-10-31 13:29:09 +00:00
Paweł Gronowski fb103cb982
Merge pull request #5583 from thaJeztah/bump_golang_1.23.2
update to go1.23.2
2024-10-31 13:10:28 +00:00
Sebastiaan van Stijn 42cda38840
update to go1.23.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-31 13:04:02 +01:00
Sebastiaan van Stijn 5e51513a8b
Merge pull request #5585 from thaJeztah/bump_golangci_lint
bump golangci-lint to v1.61.0 and cleanup config
2024-10-31 13:03:00 +01:00
Giedrius Jonikas 0b16070ae6 Buffer 'docker stats' text to avoid terminal flickering
This change reduces the flickering of the terminal when
running `docker stats` by buffering the formatted stats
text and printing it in one write.

Should also consume less CPU as we now only have to issue
a single syscall to write the stats text to the terminal.

Signed-off-by: Giedrius Jonikas <giedriusj1@gmail.com>
2024-10-31 11:23:57 +00:00
Sebastiaan van Stijn 9af049c618
bump golangci-lint to v1.61.0
Also updating a linter that was deprecated;

    The linter 'exportloopref' is deprecated (since v1.60.2) due to: Since Go1.22 (loopvar) this linter is no longer relevant. Replaced by copyloopvar.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-30 15:54:47 +01:00
Sebastiaan van Stijn 745629bd55
golangci-lint: update comment, and disable "exclude-dirs-use-default"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-30 15:52:18 +01:00
Sebastiaan van Stijn 7451339ab0
golangci-lint: move gosec excludes to linters-settings
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-30 15:52:18 +01:00
Sebastiaan van Stijn 020f3a7ad9
golangci-lint: enable G204, add #nosec comments instead
There's only 3 locations where it's hit, so putting #gosec ignore comments
in those locations.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-30 15:52:18 +01:00
Sebastiaan van Stijn aa331e94cc
Merge pull request #5579 from thaJeztah/remove_warning
cli/command/container: parse: remove client-side warning
2024-10-30 10:50:34 +01:00
Sebastiaan van Stijn 1875d9fdcb
Merge pull request #5538 from albers/completion-events--filter
Completion for `events --filter`
2024-10-29 17:58:16 +01:00
Harald Albers e1c5180dba Add tests for completions that call the API
Signed-off-by: Harald Albers <github@albersweb.de>
2024-10-29 15:58:17 +00:00
Harald Albers d4f4cf1418 Add completion for `events --filter`
Signed-off-by: Harald Albers <github@albersweb.de>
2024-10-29 15:58:17 +00:00
Sebastiaan van Stijn 59b90305f7
cli/command/container: parse: remove client-side warning
remove a client-side warning about volume drivers combined with "mounts"
in favor of producing the warning on the daemon side.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-28 23:13:31 +01:00
Sebastiaan van Stijn 32ff200fe6
Merge pull request #5573 from thaJeztah/inspect_add_configs
docker inspect: add support for swarm configs
2024-10-25 17:38:47 +02:00
Sebastiaan van Stijn e9ae9f788b
docker inspect: add support for swarm configs
The docker inspect command did not inspect configs. This patch adds support for
it, and while at it, also sorts the list of objects in runInspect.

Before this patch:

    docker config create myconfig ./codecov.yml
    danpeyh8qzb30vgdj9fr665l1

    docker inspect --format='{{.ID}}' myconfig
    []
    Error: No such object: myconfig

    docker inspect --format='{{.ID}}' --type=config myconfig
    "config" is not a valid value for --type

With this patch:

    docker inspect --format='{{.ID}}' myconfig
    danpeyh8qzb30vgdj9fr665l1

    docker inspect --format='{{.ID}}' --type=config myconfig
    danpeyh8qzb30vgdj9fr665l1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-24 18:32:32 +02:00
Piotr Ostrowski b1c7307ff1 feat: add 'docker containers' alias to match the 'docker images' logic
Signed-off-by: Piotr Ostrowski <piotrostr@google.com>
2022-08-29 15:52:57 +02:00
682 changed files with 35022 additions and 9826 deletions

View File

@ -62,7 +62,7 @@ jobs:
name: Update Go name: Update Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.22.8 go-version: 1.23.2
- -
name: Initialize CodeQL name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v3

View File

@ -68,7 +68,7 @@ jobs:
name: Set up Go name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.22.8 go-version: 1.23.2
- -
name: Test name: Test
run: | run: |

View File

@ -1,12 +1,12 @@
linters: linters:
enable: enable:
- bodyclose - bodyclose
- copyloopvar # Detects places where loop variables are copied.
- depguard - depguard
- dogsled - dogsled
- dupword # Detects duplicate words. - dupword # Detects duplicate words.
- durationcheck - durationcheck
- errchkjson - errchkjson
- exportloopref # Detects pointers to enclosing loop variables.
- gocritic # Metalinter; detects bugs, performance, and styling issues. - gocritic # Metalinter; detects bugs, performance, and styling issues.
- gocyclo - gocyclo
- gofumpt # Detects whether code was gofumpt-ed. - gofumpt # Detects whether code was gofumpt-ed.
@ -41,6 +41,9 @@ linters:
- errcheck - errcheck
run: run:
# prevent golangci-lint from deducting the go version to lint for through go.mod,
# which causes it to fallback to go1.17 semantics.
go: "1.23.2"
timeout: 5m timeout: 5m
linters-settings: linters-settings:
@ -52,6 +55,13 @@ linters-settings:
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
gocyclo: gocyclo:
min-complexity: 16 min-complexity: 16
gosec:
excludes:
- G104 # G104: Errors unhandled; (TODO: reduce unhandled errors, or explicitly ignore)
- G113 # G113: Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772); (only affects go < 1.16.14. and go < 1.17.7)
- G115 # G115: integer overflow conversion; (TODO: verify these: https://github.com/docker/cli/issues/5584)
- G306 # G306: Expect WriteFile permissions to be 0600 or less (too restrictive; also flags "0o644" permissions)
- G307 # G307: Deferring unsafe method "*os.File" on type "Close" (also EXC0008); (TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close")
govet: govet:
enable: enable:
- shadow - shadow
@ -87,6 +97,10 @@ issues:
# The default exclusion rules are a bit too permissive, so copying the relevant ones below # The default exclusion rules are a bit too permissive, so copying the relevant ones below
exclude-use-default: false exclude-use-default: false
# This option has been defined when Go modules was not existed and when the
# golangci-lint core was different, this is not something we still recommend.
exclude-dirs-use-default: false
exclude: exclude:
- parameter .* always receives - parameter .* always receives
@ -104,6 +118,9 @@ issues:
# #
# These exclusion patterns are copied from the default excluses at: # These exclusion patterns are copied from the default excluses at:
# https://github.com/golangci/golangci-lint/blob/v1.44.0/pkg/config/issues.go#L10-L104 # https://github.com/golangci/golangci-lint/blob/v1.44.0/pkg/config/issues.go#L10-L104
#
# The default list of exclusions can be found at:
# https://golangci-lint.run/usage/false-positives/#default-exclusions
# EXC0001 # EXC0001
- text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked" - text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
@ -121,11 +138,6 @@ issues:
- text: "Subprocess launch(ed with variable|ing should be audited)" - text: "Subprocess launch(ed with variable|ing should be audited)"
linters: linters:
- gosec - gosec
# EXC0008
# TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close" (gosec)
- text: "G307"
linters:
- gosec
# EXC0009 # EXC0009
- text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)" - text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)"
linters: linters:
@ -135,26 +147,6 @@ issues:
linters: linters:
- gosec - gosec
# G113 Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)
# only affects gp < 1.16.14. and go < 1.17.7
- text: "G113"
linters:
- gosec
# TODO: G104: Errors unhandled. (gosec)
- text: "G104"
linters:
- gosec
# Looks like the match in "EXC0007" above doesn't catch this one
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
- text: "G204: Subprocess launched with a potential tainted input or cmd arguments"
linters:
- gosec
# Looks like the match in "EXC0009" above doesn't catch this one
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
- text: "G306: Expect WriteFile permissions to be 0600 or less"
linters:
- gosec
# TODO: make sure all packages have a description. Currently, there's 67 packages without. # TODO: make sure all packages have a description. Currently, there's 67 packages without.
- text: "package-comments: should have a package comment" - text: "package-comments: should have a package comment"
linters: linters:

View File

@ -4,7 +4,7 @@ ARG BASE_VARIANT=alpine
ARG ALPINE_VERSION=3.20 ARG ALPINE_VERSION=3.20
ARG BASE_DEBIAN_DISTRO=bookworm ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.22.8 ARG GO_VERSION=1.23.2
ARG XX_VERSION=1.5.0 ARG XX_VERSION=1.5.0
ARG GOVERSIONINFO_VERSION=v1.3.0 ARG GOVERSIONINFO_VERSION=v1.3.0
ARG GOTESTSUM_VERSION=v1.10.0 ARG GOTESTSUM_VERSION=v1.10.0

View File

@ -17,5 +17,5 @@ func (c *candidate) Path() string {
} }
func (c *candidate) Metadata() ([]byte, error) { func (c *candidate) Metadata() ([]byte, error) {
return exec.Command(c.path, MetadataSubcommandName).Output() return exec.Command(c.path, MetadataSubcommandName).Output() // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
} }

View File

@ -52,7 +52,6 @@ func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err e
return return
} }
for _, p := range plugins { for _, p := range plugins {
p := p
vendor := p.Vendor vendor := p.Vendor
if vendor == "" { if vendor == "" {
vendor = "unknown" vendor = "unknown"

View File

@ -240,7 +240,8 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
// TODO: why are we not returning plugin.Err? // TODO: why are we not returning plugin.Err?
return nil, errPluginNotFound(name) return nil, errPluginNotFound(name)
} }
cmd := exec.Command(plugin.Path, args...) cmd := exec.Command(plugin.Path, args...) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
// Using dockerCli.{In,Out,Err}() here results in a hang until something is input. // Using dockerCli.{In,Out,Err}() here results in a hang until something is input.
// See: - https://github.com/golang/go/issues/10338 // See: - https://github.com/golang/go/issues/10338
// - https://github.com/golang/go/commit/d000e8742a173aa0659584aa01b7ba2834ba28ab // - https://github.com/golang/go/commit/d000e8742a173aa0659584aa01b7ba2834ba28ab

View File

@ -112,7 +112,7 @@ func (p *Plugin) RunHook(ctx context.Context, hookData HookPluginData) ([]byte,
return nil, wrapAsPluginError(err, "failed to marshall hook data") return nil, wrapAsPluginError(err, "failed to marshall hook data")
} }
pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes)) pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes)) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
pCmd.Env = os.Environ() pCmd.Env = os.Environ()
pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0]) pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0])
hookCmdOutput, err := pCmd.Output() hookCmdOutput, err := pCmd.Output()

View File

@ -187,19 +187,18 @@ func TestInitializeFromClient(t *testing.T) {
}, },
} }
for _, testcase := range testcases { for _, tc := range testcases {
testcase := testcase t.Run(tc.doc, func(t *testing.T) {
t.Run(testcase.doc, func(t *testing.T) {
apiclient := &fakeClient{ apiclient := &fakeClient{
pingFunc: testcase.pingFunc, pingFunc: tc.pingFunc,
version: defaultVersion, version: defaultVersion,
} }
cli := &DockerCli{client: apiclient} cli := &DockerCli{client: apiclient}
err := cli.Initialize(flags.NewClientOptions()) err := cli.Initialize(flags.NewClientOptions())
assert.NilError(t, err) assert.NilError(t, err)
assert.DeepEqual(t, cli.ServerInfo(), testcase.expectedServer) assert.DeepEqual(t, cli.ServerInfo(), tc.expectedServer)
assert.Equal(t, apiclient.negotiated, testcase.negotiated) assert.Equal(t, apiclient.negotiated, tc.negotiated)
}) })
} }
} }
@ -277,10 +276,9 @@ func TestExperimentalCLI(t *testing.T) {
}, },
} }
for _, testcase := range testcases { for _, tc := range testcases {
testcase := testcase t.Run(tc.doc, func(t *testing.T) {
t.Run(testcase.doc, func(t *testing.T) { dir := fs.NewDir(t, tc.doc, fs.WithFile("config.json", tc.configfile))
dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
defer dir.Remove() defer dir.Remove()
apiclient := &fakeClient{ apiclient := &fakeClient{
version: defaultVersion, version: defaultVersion,

View File

@ -150,7 +150,6 @@ func TestCompleteContainerNames(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
if tc.showIDs { if tc.showIDs {
t.Setenv("DOCKER_COMPLETION_SHOW_CONTAINER_IDS", "yes") t.Setenv("DOCKER_COMPLETION_SHOW_CONTAINER_IDS", "yes")
@ -227,7 +226,6 @@ func TestCompleteImageNames(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
comp := ImageNames(fakeCLI{&fakeClient{ comp := ImageNames(fakeCLI{&fakeClient{
imageListFunc: func(options image.ListOptions) ([]image.Summary, error) { imageListFunc: func(options image.ListOptions) ([]image.Summary, error) {
@ -273,7 +271,6 @@ func TestCompleteNetworkNames(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
comp := NetworkNames(fakeCLI{&fakeClient{ comp := NetworkNames(fakeCLI{&fakeClient{
networkListFunc: func(ctx context.Context, options network.ListOptions) ([]network.Summary, error) { networkListFunc: func(ctx context.Context, options network.ListOptions) ([]network.Summary, error) {
@ -331,7 +328,6 @@ func TestCompleteVolumeNames(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
comp := VolumeNames(fakeCLI{&fakeClient{ comp := VolumeNames(fakeCLI{&fakeClient{
volumeListFunc: func(filter filters.Args) (volume.ListResponse, error) { volumeListFunc: func(filter filters.Args) (volume.ListResponse, error) {

View File

@ -43,7 +43,6 @@ func TestConfigCreateErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.expectedError, func(t *testing.T) { t.Run(tc.expectedError, func(t *testing.T) {
cmd := newConfigCreateCommand( cmd := newConfigCreateCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{

View File

@ -61,7 +61,6 @@ id_rsa
}, },
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -73,7 +73,6 @@ func TestNewAttachCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewAttachCommand(test.NewFakeCli(&fakeClient{inspectFunc: tc.containerInspectFunc})) cmd := NewAttachCommand(test.NewFakeCli(&fakeClient{inspectFunc: tc.containerInspectFunc}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)

View File

@ -178,7 +178,6 @@ func TestSplitCpArg(t *testing.T) {
}, },
} }
for _, tc := range testcases { for _, tc := range testcases {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
if tc.os == "windows" && runtime.GOOS != "windows" { if tc.os == "windows" && runtime.GOOS != "windows" {
t.Skip("skipping windows test on non-windows platform") t.Skip("skipping windows test on non-windows platform")

View File

@ -113,7 +113,6 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(tc.PullPolicy, func(t *testing.T) { t.Run(tc.PullPolicy, func(t *testing.T) {
pullCounter := 0 pullCounter := 0
@ -176,7 +175,6 @@ func TestCreateContainerImagePullPolicyInvalid(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(tc.PullPolicy, func(t *testing.T) { t.Run(tc.PullPolicy, func(t *testing.T) {
dockerCli := test.NewFakeCli(&fakeClient{}) dockerCli := test.NewFakeCli(&fakeClient{})
err := runCreate( err := runCreate(
@ -207,7 +205,6 @@ func TestCreateContainerValidateFlags(t *testing.T) {
expectedErr: `invalid argument "STDINFO" for "-a, --attach" flag: valid streams are STDIN, STDOUT and STDERR`, expectedErr: `invalid argument "STDINFO" for "-a, --attach" flag: valid streams are STDIN, STDOUT and STDERR`,
}, },
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewCreateCommand(test.NewFakeCli(&fakeClient{})) cmd := NewCreateCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)
@ -251,7 +248,6 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
fakeCLI := test.NewFakeCli(&fakeClient{ fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config, createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig, hostConfig *container.HostConfig,
@ -312,7 +308,6 @@ func TestNewCreateCommandWithWarnings(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
fakeCLI := test.NewFakeCli(&fakeClient{ fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config, createContainerFunc: func(config *container.Config,

View File

@ -47,7 +47,6 @@ D: /usr/app/old_app.js
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
out := bytes.NewBufferString("") out := bytes.NewBufferString("")
tc.context.Output = out tc.context.Output = out

View File

@ -178,7 +178,6 @@ container2 -- --
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out
@ -223,7 +222,6 @@ func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
err := statsFormatWrite(tc.context, []StatsEntry{}, "linux", false) err := statsFormatWrite(tc.context, []StatsEntry{}, "linux", false)
assert.NilError(t, err) assert.NilError(t, err)
@ -265,7 +263,6 @@ func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
err := statsFormatWrite(tc.context, []StatsEntry{}, "windows", false) err := statsFormatWrite(tc.context, []StatsEntry{}, "windows", false)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -42,7 +42,7 @@ func NewPsCommand(dockerCLI command.Cli) *cobra.Command {
}, },
Annotations: map[string]string{ Annotations: map[string]string{
"category-top": "3", "category-top": "3",
"aliases": "docker container ls, docker container list, docker container ps, docker ps", "aliases": "docker container ls, docker container list, docker container ps, docker ps, docker containers",
}, },
ValidArgsFunction: completion.NoComplete, ValidArgsFunction: completion.NoComplete,
} }

View File

@ -277,7 +277,6 @@ func TestContainerListFormatSizeSetsOption(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
containerListFunc: func(options container.ListOptions) ([]container.Summary, error) { containerListFunc: func(options container.ListOptions) ([]container.Summary, error) {

View File

@ -23,7 +23,6 @@ import (
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag" "github.com/spf13/pflag"
cdi "tags.cncf.io/container-device-interface/pkg/parser" cdi "tags.cncf.io/container-device-interface/pkg/parser"
) )
@ -364,10 +363,6 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
return nil, errors.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness) return nil, errors.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness)
} }
mounts := copts.mounts.Value()
if len(mounts) > 0 && copts.volumeDriver != "" {
logrus.Warn("`--volume-driver` is ignored for volumes specified via `--mount`. Use `--mount type=volume,volume-driver=...` instead.")
}
var binds []string var binds []string
volumes := copts.volumes.GetMap() volumes := copts.volumes.GetMap()
// add any bind targets to the list of container volumes // add any bind targets to the list of container volumes
@ -697,7 +692,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
Tmpfs: tmpfs, Tmpfs: tmpfs,
Sysctls: copts.sysctls.GetAll(), Sysctls: copts.sysctls.GetAll(),
Runtime: copts.runtime, Runtime: copts.runtime,
Mounts: mounts, Mounts: copts.mounts.Value(),
MaskedPaths: maskedPaths, MaskedPaths: maskedPaths,
ReadonlyPaths: readonlyPaths, ReadonlyPaths: readonlyPaths,
Annotations: copts.annotations.GetAll(), Annotations: copts.annotations.GetAll(),
@ -767,7 +762,6 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*networktypes.Endpoin
} }
for i, n := range copts.netMode.Value() { for i, n := range copts.netMode.Value() {
n := n
if container.NetworkMode(n.Target).IsUserDefined() { if container.NetworkMode(n.Target).IsUserDefined() {
hasUserDefined = true hasUserDefined = true
} else { } else {

View File

@ -126,7 +126,6 @@ func TestParseRunAttach(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.input, func(t *testing.T) { t.Run(tc.input, func(t *testing.T) {
config, _, _ := mustParse(t, tc.input) config, _, _ := mustParse(t, tc.input)
assert.Equal(t, config.AttachStdin, tc.expected.AttachStdin) assert.Equal(t, config.AttachStdin, tc.expected.AttachStdin)
@ -802,7 +801,6 @@ func TestParseRestartPolicy(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.input, func(t *testing.T) { t.Run(tc.input, func(t *testing.T) {
_, hostConfig, _, err := parseRun([]string{"--restart=" + tc.input, "img", "cmd"}) _, hostConfig, _, err := parseRun([]string{"--restart=" + tc.input, "img", "cmd"})
if tc.expectedErr != "" { if tc.expectedErr != "" {

View File

@ -43,7 +43,6 @@ func TestNewPortCommandOutput(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
inspectFunc: func(string) (container.InspectResponse, error) { inspectFunc: func(string) (container.InspectResponse, error) {

View File

@ -58,7 +58,6 @@ func TestRestart(t *testing.T) {
expectedErr: "conflicting options: cannot specify both --timeout and --time", expectedErr: "conflicting options: cannot specify both --timeout and --time",
}, },
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
var restarted []string var restarted []string
mutex := new(sync.Mutex) mutex := new(sync.Mutex)

View File

@ -23,7 +23,6 @@ func TestRemoveForce(t *testing.T) {
{name: "without force", args: []string{"nosuchcontainer", "mycontainer"}, expectedErr: "no such container"}, {name: "without force", args: []string{"nosuchcontainer", "mycontainer"}, expectedErr: "no such container"},
{name: "with force", args: []string{"--force", "nosuchcontainer", "mycontainer"}, expectedErr: ""}, {name: "with force", args: []string{"--force", "nosuchcontainer", "mycontainer"}, expectedErr: ""},
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
var removed []string var removed []string
mutex := new(sync.Mutex) mutex := new(sync.Mutex)

View File

@ -35,7 +35,6 @@ func TestRunValidateFlags(t *testing.T) {
expectedErr: "conflicting options: cannot specify both --attach and --detach", expectedErr: "conflicting options: cannot specify both --attach and --detach",
}, },
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewRunCommand(test.NewFakeCli(&fakeClient{})) cmd := NewRunCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)
@ -245,7 +244,6 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
fakeCLI := test.NewFakeCli(&fakeClient{ fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config, createContainerFunc: func(config *container.Config,
@ -286,7 +284,6 @@ func TestRunContainerImagePullPolicyInvalid(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(tc.PullPolicy, func(t *testing.T) { t.Run(tc.PullPolicy, func(t *testing.T) {
dockerCli := test.NewFakeCli(&fakeClient{}) dockerCli := test.NewFakeCli(&fakeClient{})
err := runRun( err := runRun(

View File

@ -1,6 +1,7 @@
package container package container
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -264,31 +265,40 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
// so we unlikely hit this code in practice. // so we unlikely hit this code in practice.
daemonOSType = dockerCLI.ServerInfo().OSType daemonOSType = dockerCLI.ServerInfo().OSType
} }
// Buffer to store formatted stats text.
// Once formatted, it will be printed in one write to avoid screen flickering.
var statsTextBuffer bytes.Buffer
statsCtx := formatter.Context{ statsCtx := formatter.Context{
Output: dockerCLI.Out(), Output: &statsTextBuffer,
Format: NewStatsFormat(format, daemonOSType), Format: NewStatsFormat(format, daemonOSType),
} }
cleanScreen := func() {
if !options.NoStream {
_, _ = fmt.Fprint(dockerCLI.Out(), "\033[2J")
_, _ = fmt.Fprint(dockerCLI.Out(), "\033[H")
}
}
var err error var err error
ticker := time.NewTicker(500 * time.Millisecond) ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C { for range ticker.C {
cleanScreen()
var ccStats []StatsEntry var ccStats []StatsEntry
cStats.mu.RLock() cStats.mu.RLock()
for _, c := range cStats.cs { for _, c := range cStats.cs {
ccStats = append(ccStats, c.GetStatistics()) ccStats = append(ccStats, c.GetStatistics())
} }
cStats.mu.RUnlock() cStats.mu.RUnlock()
if !options.NoStream {
// Start by clearing the screen and moving the cursor to the top-left
_, _ = fmt.Fprint(&statsTextBuffer, "\033[2J\033[H")
}
if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil { if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
break break
} }
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
statsTextBuffer.Reset()
if len(cStats.cs) == 0 && !showAll { if len(cStats.cs) == 0 && !showAll {
break break
} }

View File

@ -58,7 +58,6 @@ func TestStop(t *testing.T) {
expectedErr: "conflicting options: cannot specify both --timeout and --time", expectedErr: "conflicting options: cannot specify both --timeout and --time",
}, },
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
var stopped []string var stopped []string
mutex := new(sync.Mutex) mutex := new(sync.Mutex)

View File

@ -94,7 +94,6 @@ func TestCreate(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.options.Name, func(t *testing.T) { t.Run(tc.options.Name, func(t *testing.T) {
err := RunCreate(cli, &tc.options) err := RunCreate(cli, &tc.options)
if tc.expecterErr == "" { if tc.expecterErr == "" {
@ -164,25 +163,24 @@ func TestCreateFromContext(t *testing.T) {
cli.SetCurrentContext("dummy") cli.SetCurrentContext("dummy")
for _, c := range cases { for _, tc := range cases {
c := c t.Run(tc.name, func(t *testing.T) {
t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{ err := RunCreate(cli, &CreateOptions{
From: "original", From: "original",
Name: c.name, Name: tc.name,
Description: c.description, Description: tc.description,
Docker: c.docker, Docker: tc.docker,
}) })
assert.NilError(t, err) assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name) assertContextCreateLogging(t, cli, tc.name)
newContext, err := cli.ContextStore().GetMetadata(c.name) newContext, err := cli.ContextStore().GetMetadata(tc.name)
assert.NilError(t, err) assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext) newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext) dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, c.expectedDescription) assert.Equal(t, newContextTyped.Description, tc.expectedDescription)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
}) })
} }
@ -219,23 +217,22 @@ func TestCreateFromCurrent(t *testing.T) {
cli.SetCurrentContext("original") cli.SetCurrentContext("original")
for _, c := range cases { for _, tc := range cases {
c := c t.Run(tc.name, func(t *testing.T) {
t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers() cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{ err := RunCreate(cli, &CreateOptions{
Name: c.name, Name: tc.name,
Description: c.description, Description: tc.description,
}) })
assert.NilError(t, err) assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name) assertContextCreateLogging(t, cli, tc.name)
newContext, err := cli.ContextStore().GetMetadata(c.name) newContext, err := cli.ContextStore().GetMetadata(tc.name)
assert.NilError(t, err) assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext) newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext) dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, c.expectedDescription) assert.Equal(t, newContextTyped.Description, tc.expectedDescription)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
}) })
} }

View File

@ -346,7 +346,6 @@ size: 0B
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out
@ -411,7 +410,6 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
err := ContainerWrite(tc.context, containers) err := ContainerWrite(tc.context, containers)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -106,7 +106,6 @@ Build Cache 0 0 0B 0B
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -304,7 +304,6 @@ image_id: imageID3
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out
@ -365,7 +364,6 @@ func TestImageContextWriteWithNoImage(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
err := ImageWrite(tc.context, images) err := ImageWrite(tc.context, images)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -131,7 +131,6 @@ foobar_bar
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -255,7 +255,6 @@ imageID6 17 years ago /bin/bash echo 183MB
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
err := HistoryWrite(tc.context, true, histories) err := HistoryWrite(tc.context, true, histories)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -42,7 +42,6 @@ func TestNewHistoryCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewHistoryCommand(test.NewFakeCli(&fakeClient{imageHistoryFunc: tc.imageHistoryFunc})) cmd := NewHistoryCommand(test.NewFakeCli(&fakeClient{imageHistoryFunc: tc.imageHistoryFunc}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)
@ -109,7 +108,6 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// Set to UTC timezone as timestamps in output are // Set to UTC timezone as timestamps in output are
// printed in the current timezone // printed in the current timezone

View File

@ -98,7 +98,6 @@ func TestNewImportCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc})) cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)

View File

@ -25,7 +25,6 @@ func TestNewInspectCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newInspectCommand(test.NewFakeCli(&fakeClient{})) cmd := newInspectCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)
@ -79,7 +78,6 @@ func TestNewInspectCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
imageInspectInvocationCount = 0 imageInspectInvocationCount = 0
cli := test.NewFakeCli(&fakeClient{imageInspectFunc: tc.imageInspectFunc}) cli := test.NewFakeCli(&fakeClient{imageInspectFunc: tc.imageInspectFunc})

View File

@ -35,7 +35,6 @@ func TestNewImagesCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewImagesCommand(test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc})) cmd := NewImagesCommand(test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc}))
cmd.SetOut(io.Discard) cmd.SetOut(io.Discard)
@ -83,7 +82,6 @@ func TestNewImagesCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc}) cli := test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc})
cli.SetConfigFile(&configfile.ConfigFile{ImagesFormat: tc.imageFormat}) cli.SetConfigFile(&configfile.ConfigFile{ImagesFormat: tc.imageFormat})

View File

@ -52,7 +52,6 @@ func TestNewLoadCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageLoadFunc: tc.imageLoadFunc}) cli := test.NewFakeCli(&fakeClient{imageLoadFunc: tc.imageLoadFunc})
cli.In().SetIsTerminal(tc.isTerminalIn) cli.In().SetIsTerminal(tc.isTerminalIn)
@ -116,7 +115,6 @@ func TestNewLoadCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageLoadFunc: tc.imageLoadFunc}) cli := test.NewFakeCli(&fakeClient{imageLoadFunc: tc.imageLoadFunc})
cmd := NewLoadCommand(cli) cmd := NewLoadCommand(cli)

View File

@ -39,7 +39,6 @@ func TestNewPruneCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewPruneCommand(test.NewFakeCli(&fakeClient{ cmd := NewPruneCommand(test.NewFakeCli(&fakeClient{
imagesPruneFunc: tc.imagesPruneFunc, imagesPruneFunc: tc.imagesPruneFunc,
@ -98,7 +97,6 @@ func TestNewPruneCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imagesPruneFunc: tc.imagesPruneFunc}) cli := test.NewFakeCli(&fakeClient{imagesPruneFunc: tc.imagesPruneFunc})
// when prompted, answer "Y" to confirm the prune. // when prompted, answer "Y" to confirm the prune.

View File

@ -38,7 +38,6 @@ func TestNewPullCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})
cmd := NewPullCommand(cli) cmd := NewPullCommand(cli)
@ -73,7 +72,6 @@ func TestNewPullCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) { imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) {
@ -119,7 +117,6 @@ func TestNewPullCommandWithContentTrustErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) { imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) {

View File

@ -38,7 +38,6 @@ func TestNewPushCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imagePushFunc: tc.imagePushFunc}) cli := test.NewFakeCli(&fakeClient{imagePushFunc: tc.imagePushFunc})
cmd := NewPushCommand(cli) cmd := NewPushCommand(cli)
@ -68,7 +67,6 @@ func TestNewPushCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
imagePushFunc: func(ref string, options image.PushOptions) (io.ReadCloser, error) { imagePushFunc: func(ref string, options image.PushOptions) (io.ReadCloser, error) {

View File

@ -62,7 +62,6 @@ func TestNewRemoveCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewRemoveCommand(test.NewFakeCli(&fakeClient{ cmd := NewRemoveCommand(test.NewFakeCli(&fakeClient{
imageRemoveFunc: tc.imageRemoveFunc, imageRemoveFunc: tc.imageRemoveFunc,
@ -121,7 +120,6 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc}) cli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc})
cmd := NewRemoveCommand(cli) cmd := NewRemoveCommand(cli)

View File

@ -59,7 +59,6 @@ func TestNewSaveCommandErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageSaveFunc: tc.imageSaveFunc}) cli := test.NewFakeCli(&fakeClient{imageSaveFunc: tc.imageSaveFunc})
cli.Out().SetIsTerminal(tc.isTerminal) cli.Out().SetIsTerminal(tc.isTerminal)
@ -113,7 +112,6 @@ func TestNewSaveCommandSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(strings.Join(tc.args, " "), func(t *testing.T) { t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
cmd := NewSaveCommand(test.NewFakeCli(&fakeClient{ cmd := NewSaveCommand(test.NewFakeCli(&fakeClient{
imageSaveFunc: tc.imageSaveFunc, imageSaveFunc: tc.imageSaveFunc,

View File

@ -56,7 +56,6 @@ func runTree(ctx context.Context, dockerCLI command.Cli, opts treeOptions) error
continue continue
} }
im := im
sub := subImage{ sub := subImage{
Platform: platforms.Format(im.ImageData.Platform), Platform: platforms.Format(im.ImageData.Platform),
Available: im.Available, Available: im.Available,

View File

@ -31,7 +31,6 @@ func TestManifestCreateErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.expectedError, func(t *testing.T) { t.Run(tc.expectedError, func(t *testing.T) {
cli := test.NewFakeCli(nil) cli := test.NewFakeCli(nil)
cmd := newCreateListCommand(cli) cmd := newCreateListCommand(cli)

View File

@ -218,7 +218,6 @@ func TestNetworkCreateIPv6(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
networkCreateFunc: func(ctx context.Context, name string, createBody network.CreateOptions) (network.CreateResponse, error) { networkCreateFunc: func(ctx context.Context, name string, createBody network.CreateOptions) (network.CreateResponse, error) {

View File

@ -161,7 +161,6 @@ foobar_bar 2017-01-01 00:00:00 +0000 UTC
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -83,7 +83,6 @@ func TestNetworkList(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{networkListFunc: tc.networkListFunc}) cli := test.NewFakeCli(&fakeClient{networkListFunc: tc.networkListFunc})
cmd := newListCommand(cli) cmd := newListCommand(cli)

View File

@ -63,7 +63,6 @@ func TestNetworkRemoveForce(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
fakeCli := test.NewFakeCli(&fakeClient{ fakeCli := test.NewFakeCli(&fakeClient{
networkRemoveFunc: func(ctx context.Context, networkID string) error { networkRemoveFunc: func(ctx context.Context, networkID string) error {

View File

@ -202,7 +202,6 @@ foobar_boo Unknown
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -106,7 +106,6 @@ func TestNodeInspectPretty(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
nodeInspectFunc: tc.nodeInspectFunc, nodeInspectFunc: tc.nodeInspectFunc,

View File

@ -134,7 +134,6 @@ func TestNodePs(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
infoFunc: tc.infoFunc, infoFunc: tc.infoFunc,

View File

@ -131,7 +131,6 @@ foobar_bar
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -66,7 +66,6 @@ func TestInspectErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc}) cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc})
cmd := newInspectCommand(cli) cmd := newInspectCommand(cli)
@ -138,7 +137,6 @@ func TestInspect(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc}) cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc})
cmd := newInspectCommand(cli) cmd := newInspectCommand(cli)

View File

@ -54,7 +54,6 @@ func TestInstallErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc}) cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc})
cmd := newInstallCommand(cli) cmd := newInstallCommand(cli)
@ -94,7 +93,6 @@ func TestInstallContentTrustErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
pluginInstallFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { pluginInstallFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) {
@ -138,7 +136,6 @@ func TestInstall(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc}) cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc})
cmd := newInstallCommand(cli) cmd := newInstallCommand(cli)

View File

@ -46,7 +46,6 @@ func TestListErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc}) cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
cmd := newListCommand(cli) cmd := newListCommand(cli)
@ -166,7 +165,6 @@ func TestList(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc}) cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
cmd := newListCommand(cli) cmd := newListCommand(cli)

View File

@ -203,7 +203,6 @@ result2 5
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
err := SearchWrite(formatter.Context{Format: tc.format, Output: &out}, results) err := SearchWrite(formatter.Context{Format: tc.format, Output: &out}, results)

View File

@ -61,7 +61,6 @@ id_rsa
}, },
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -93,7 +93,6 @@ func TestSecretInspectWithoutFormat(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
secretInspectFunc: tc.secretInspectFunc, secretInspectFunc: tc.secretInspectFunc,
@ -132,7 +131,6 @@ func TestSecretInspectWithFormat(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
secretInspectFunc: tc.secretInspectFunc, secretInspectFunc: tc.secretInspectFunc,

View File

@ -223,7 +223,6 @@ zarp2
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -168,7 +168,6 @@ func TestServiceListServiceStatus(t *testing.T) {
} }
for _, tc := range matrix { for _, tc := range matrix {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
if tc.cluster == nil { if tc.cluster == nil {
tc.cluster = generateCluster(t, tc.opts) tc.cluster = generateCluster(t, tc.opts)

View File

@ -50,7 +50,6 @@ func TestCredentialSpecOpt(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
var cs credentialSpecOpt var cs credentialSpecOpt

View File

@ -91,7 +91,6 @@ func TestRollbackWithErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newRollbackCommand( cmd := newRollbackCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{

View File

@ -1058,7 +1058,6 @@ func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error {
// Build the current list of portConfig // Build the current list of portConfig
for _, entry := range *portConfig { for _, entry := range *portConfig {
entry := entry
if _, ok := portSet[portConfigToString(&entry)]; !ok { if _, ok := portSet[portConfigToString(&entry)]; !ok {
portSet[portConfigToString(&entry)] = entry portSet[portConfigToString(&entry)] = entry
} }
@ -1086,7 +1085,6 @@ portLoop:
ports := flags.Lookup(flagPublishAdd).Value.(*opts.PortOpt).Value() ports := flags.Lookup(flagPublishAdd).Value.(*opts.PortOpt).Value()
for _, port := range ports { for _, port := range ports {
port := port
if _, ok := portSet[portConfigToString(&port)]; ok { if _, ok := portSet[portConfigToString(&port)]; ok {
continue continue
} }

View File

@ -1690,7 +1690,6 @@ func TestUpdateUlimits(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
svc := swarm.ServiceSpec{ svc := swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{ TaskTemplate: swarm.TaskSpec{

View File

@ -51,7 +51,6 @@ bar
{Name: "bar", Services: 1}, {Name: "bar", Services: 1},
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -48,7 +48,6 @@ func TestListErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.expectedError, func(t *testing.T) { t.Run(tc.expectedError, func(t *testing.T) {
cmd := newListCommand(test.NewFakeCli(&fakeClient{ cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc, serviceListFunc: tc.serviceListFunc,
@ -104,7 +103,6 @@ func TestStackList(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
var services []swarm.Service var services []swarm.Service
for _, name := range tc.serviceNames { for _, name := range tc.serviceNames {

View File

@ -40,7 +40,6 @@ func TestStackPsErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.expectedError, func(t *testing.T) { t.Run(tc.expectedError, func(t *testing.T) {
cmd := newPsCommand(test.NewFakeCli(&fakeClient{ cmd := newPsCommand(test.NewFakeCli(&fakeClient{
taskListFunc: tc.taskListFunc, taskListFunc: tc.taskListFunc,
@ -160,7 +159,6 @@ func TestStackPs(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
taskListFunc: tc.taskListFunc, taskListFunc: tc.taskListFunc,

View File

@ -67,7 +67,6 @@ func TestStackServicesErrors(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.expectedError, func(t *testing.T) { t.Run(tc.expectedError, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc, serviceListFunc: tc.serviceListFunc,

View File

@ -88,7 +88,6 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) {
ctx := context.Background() ctx := context.Background()
for _, tc := range testcases { for _, tc := range testcases {
tc := tc
t.Run(tc.image, func(t *testing.T) { t.Run(tc.image, func(t *testing.T) {
spec := map[string]swarm.ServiceSpec{ spec := map[string]swarm.ServiceSpec{
"myservice": { "myservice": {

View File

@ -63,7 +63,6 @@ func TestSwarmInitErrorOnAPIFailure(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newInitCommand( cmd := newInitCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{

View File

@ -48,7 +48,6 @@ func TestSwarmJoinErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newJoinCommand( cmd := newJoinCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{
@ -93,7 +92,6 @@ func TestSwarmJoin(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
infoFunc: tc.infoFunc, infoFunc: tc.infoFunc,

View File

@ -87,7 +87,6 @@ func TestSwarmJoinTokenErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
swarmInspectFunc: tc.swarmInspectFunc, swarmInspectFunc: tc.swarmInspectFunc,
@ -198,7 +197,6 @@ func TestSwarmJoinToken(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
swarmInspectFunc: tc.swarmInspectFunc, swarmInspectFunc: tc.swarmInspectFunc,

View File

@ -32,7 +32,6 @@ func TestSwarmLeaveErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newLeaveCommand( cmd := newLeaveCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{

View File

@ -80,7 +80,6 @@ func TestSwarmUnlockKeyErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newUnlockKeyCommand( cmd := newUnlockKeyCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{
@ -158,7 +157,6 @@ func TestSwarmUnlockKey(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
swarmInspectFunc: tc.swarmInspectFunc, swarmInspectFunc: tc.swarmInspectFunc,

View File

@ -64,7 +64,6 @@ func TestSwarmUnlockErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newUnlockCommand( cmd := newUnlockCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{

View File

@ -65,7 +65,6 @@ func TestSwarmUpdateErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newUpdateCommand( cmd := newUpdateCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{
@ -169,7 +168,6 @@ func TestSwarmUpdate(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
swarmInspectFunc: tc.swarmInspectFunc, swarmInspectFunc: tc.swarmInspectFunc,

View File

@ -7,7 +7,11 @@ import (
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
@ -15,22 +19,27 @@ type fakeClient struct {
client.Client client.Client
version string version string
serverVersion func(ctx context.Context) (types.Version, error) containerListFunc func(context.Context, container.ListOptions) ([]container.Summary, error)
eventsFn func(context.Context, events.ListOptions) (<-chan events.Message, <-chan error)
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
eventsFn func(context.Context, events.ListOptions) (<-chan events.Message, <-chan error)
imageListFunc func(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
infoFunc func(ctx context.Context) (system.Info, error)
networkListFunc func(ctx context.Context, options network.ListOptions) ([]network.Summary, error)
networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
} nodeListFunc func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
serverVersion func(ctx context.Context) (types.Version, error)
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) { volumeListFunc func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error)
return cli.serverVersion(ctx)
} }
func (cli *fakeClient) ClientVersion() string { func (cli *fakeClient) ClientVersion() string {
return cli.version return cli.version
} }
func (cli *fakeClient) Events(ctx context.Context, opts events.ListOptions) (<-chan events.Message, <-chan error) { func (cli *fakeClient) ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error) {
return cli.eventsFn(ctx, opts) if cli.containerListFunc != nil {
return cli.containerListFunc(ctx, options)
}
return []container.Summary{}, nil
} }
func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) { func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
@ -40,9 +49,52 @@ func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters
return container.PruneReport{}, nil return container.PruneReport{}, nil
} }
func (cli *fakeClient) Events(ctx context.Context, opts events.ListOptions) (<-chan events.Message, <-chan error) {
return cli.eventsFn(ctx, opts)
}
func (cli *fakeClient) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) {
if cli.imageListFunc != nil {
return cli.imageListFunc(ctx, options)
}
return []image.Summary{}, nil
}
func (cli *fakeClient) Info(ctx context.Context) (system.Info, error) {
if cli.infoFunc != nil {
return cli.infoFunc(ctx)
}
return system.Info{}, nil
}
func (cli *fakeClient) NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error) {
if cli.networkListFunc != nil {
return cli.networkListFunc(ctx, options)
}
return []network.Summary{}, nil
}
func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) { func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) {
if cli.networkPruneFunc != nil { if cli.networkPruneFunc != nil {
return cli.networkPruneFunc(ctx, pruneFilter) return cli.networkPruneFunc(ctx, pruneFilter)
} }
return network.PruneReport{}, nil return network.PruneReport{}, nil
} }
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc(ctx, options)
}
return []swarm.Node{}, nil
}
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) {
return cli.serverVersion(ctx)
}
func (cli *fakeClient) VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) {
if cli.volumeListFunc != nil {
return cli.volumeListFunc(ctx, options)
}
return volume.ListResponse{}, nil
}

View File

@ -0,0 +1,237 @@
package system
import (
"strings"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/spf13/cobra"
)
var (
eventFilters = []string{"container", "daemon", "event", "image", "label", "network", "node", "scope", "type", "volume"}
// eventTypes is a list of all event types.
// This should be moved to the moby codebase once its usage is consolidated here.
eventTypes = []events.Type{
events.BuilderEventType,
events.ConfigEventType,
events.ContainerEventType,
events.DaemonEventType,
events.ImageEventType,
events.NetworkEventType,
events.NodeEventType,
events.PluginEventType,
events.SecretEventType,
events.ServiceEventType,
events.VolumeEventType,
}
// eventActions is a list of all event actions.
// This should be moved to the moby codebase once its usage is consolidated here.
eventActions = []events.Action{
events.ActionCreate,
events.ActionStart,
events.ActionRestart,
events.ActionStop,
events.ActionCheckpoint,
events.ActionPause,
events.ActionUnPause,
events.ActionAttach,
events.ActionDetach,
events.ActionResize,
events.ActionUpdate,
events.ActionRename,
events.ActionKill,
events.ActionDie,
events.ActionOOM,
events.ActionDestroy,
events.ActionRemove,
events.ActionCommit,
events.ActionTop,
events.ActionCopy,
events.ActionArchivePath,
events.ActionExtractToDir,
events.ActionExport,
events.ActionImport,
events.ActionSave,
events.ActionLoad,
events.ActionTag,
events.ActionUnTag,
events.ActionPush,
events.ActionPull,
events.ActionPrune,
events.ActionDelete,
events.ActionEnable,
events.ActionDisable,
events.ActionConnect,
events.ActionDisconnect,
events.ActionReload,
events.ActionMount,
events.ActionUnmount,
events.ActionExecCreate,
events.ActionExecStart,
events.ActionExecDie,
events.ActionExecDetach,
events.ActionHealthStatus,
events.ActionHealthStatusRunning,
events.ActionHealthStatusHealthy,
events.ActionHealthStatusUnhealthy,
}
)
// completeEventFilters provides completion for the filters that can be used with `--filter`.
func completeEventFilters(dockerCLI completion.APIClientProvider) completion.ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
key, _, ok := strings.Cut(toComplete, "=")
if !ok {
return postfixWith("=", eventFilters), cobra.ShellCompDirectiveNoSpace
}
switch key {
case "container":
return prefixWith("container=", containerNames(dockerCLI, cmd, args, toComplete)), cobra.ShellCompDirectiveNoFileComp
case "daemon":
return prefixWith("daemon=", daemonNames(dockerCLI, cmd)), cobra.ShellCompDirectiveNoFileComp
case "event":
return prefixWith("event=", validEventNames()), cobra.ShellCompDirectiveNoFileComp
case "image":
return prefixWith("image=", imageNames(dockerCLI, cmd)), cobra.ShellCompDirectiveNoFileComp
case "label":
return nil, cobra.ShellCompDirectiveNoFileComp
case "network":
return prefixWith("network=", networkNames(dockerCLI, cmd)), cobra.ShellCompDirectiveNoFileComp
case "node":
return prefixWith("node=", nodeNames(dockerCLI, cmd)), cobra.ShellCompDirectiveNoFileComp
case "scope":
return prefixWith("scope=", []string{"local", "swarm"}), cobra.ShellCompDirectiveNoFileComp
case "type":
return prefixWith("type=", eventTypeNames()), cobra.ShellCompDirectiveNoFileComp
case "volume":
return prefixWith("volume=", volumeNames(dockerCLI, cmd)), cobra.ShellCompDirectiveNoFileComp
default:
return postfixWith("=", eventFilters), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
}
}
}
// prefixWith prefixes every element in the slice with the given prefix.
func prefixWith(prefix string, values []string) []string {
result := make([]string, len(values))
for i, v := range values {
result[i] = prefix + v
}
return result
}
// postfixWith appends postfix to every element in the slice.
func postfixWith(postfix string, values []string) []string {
result := make([]string, len(values))
for i, v := range values {
result[i] = v + postfix
}
return result
}
// eventTypeNames provides a list of all event types.
// The list is derived from eventTypes.
func eventTypeNames() []string {
names := make([]string, len(eventTypes))
for i, eventType := range eventTypes {
names[i] = string(eventType)
}
return names
}
// validEventNames provides a list of all event actions.
// The list is derived from eventActions.
// Actions that are not suitable for usage in completions are removed.
func validEventNames() []string {
names := make([]string, 0, len(eventActions))
for _, eventAction := range eventActions {
if strings.Contains(string(eventAction), " ") {
continue
}
names = append(names, string(eventAction))
}
return names
}
// containerNames contacts the API to get names and optionally IDs of containers.
// In case of an error, an empty list is returned.
func containerNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command, args []string, toComplete string) []string {
names, _ := completion.ContainerNames(dockerCLI, true)(cmd, args, toComplete)
if names == nil {
return []string{}
}
return names
}
// daemonNames contacts the API to get name and ID of the current docker daemon.
// In case of an error, an empty list is returned.
func daemonNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
info, err := dockerCLI.Client().Info(cmd.Context())
if err != nil {
return []string{}
}
return []string{info.Name, info.ID}
}
// imageNames contacts the API to get a list of image names.
// In case of an error, an empty list is returned.
func imageNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
list, err := dockerCLI.Client().ImageList(cmd.Context(), image.ListOptions{})
if err != nil {
return []string{}
}
names := make([]string, 0, len(list))
for _, img := range list {
names = append(names, img.RepoTags...)
}
return names
}
// networkNames contacts the API to get a list of network names.
// In case of an error, an empty list is returned.
func networkNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
list, err := dockerCLI.Client().NetworkList(cmd.Context(), network.ListOptions{})
if err != nil {
return []string{}
}
names := make([]string, 0, len(list))
for _, nw := range list {
names = append(names, nw.Name)
}
return names
}
// nodeNames contacts the API to get a list of node names.
// In case of an error, an empty list is returned.
func nodeNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
list, err := dockerCLI.Client().NodeList(cmd.Context(), types.NodeListOptions{})
if err != nil {
return []string{}
}
names := make([]string, 0, len(list))
for _, node := range list {
names = append(names, node.Description.Hostname)
}
return names
}
// volumeNames contacts the API to get a list of volume names.
// In case of an error, an empty list is returned.
func volumeNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []string {
list, err := dockerCLI.Client().VolumeList(cmd.Context(), volume.ListOptions{})
if err != nil {
return []string{}
}
names := make([]string, 0, len(list.Volumes))
for _, v := range list.Volumes {
names = append(names, v.Name)
}
return names
}

View File

@ -0,0 +1,165 @@
package system
import (
"context"
"errors"
"fmt"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/api/types/volume"
"github.com/spf13/cobra"
"gotest.tools/v3/assert"
)
func TestCompleteEventFilter(t *testing.T) {
tests := []struct {
client *fakeClient
toComplete string
expected []string
}{
{
client: &fakeClient{
containerListFunc: func(_ context.Context, _ container.ListOptions) ([]container.Summary, error) {
return []container.Summary{
*builders.Container("c1"),
*builders.Container("c2"),
}, nil
},
},
toComplete: "container=",
expected: []string{"container=c1", "container=c2"},
},
{
client: &fakeClient{
containerListFunc: func(_ context.Context, _ container.ListOptions) ([]container.Summary, error) {
return nil, errors.New("API error")
},
},
toComplete: "container=",
expected: []string{},
},
{
client: &fakeClient{
infoFunc: func(ctx context.Context) (system.Info, error) {
return system.Info{
ID: "daemon-id",
Name: "daemon-name",
}, nil
},
},
toComplete: "daemon=",
expected: []string{"daemon=daemon-name", "daemon=daemon-id"},
},
{
client: &fakeClient{
infoFunc: func(ctx context.Context) (system.Info, error) {
return system.Info{}, errors.New("API error")
},
},
toComplete: "daemon=",
expected: []string{},
},
{
client: &fakeClient{
imageListFunc: func(_ context.Context, _ image.ListOptions) ([]image.Summary, error) {
return []image.Summary{
{RepoTags: []string{"img:1"}},
{RepoTags: []string{"img:2"}},
}, nil
},
},
toComplete: "image=",
expected: []string{"image=img:1", "image=img:2"},
},
{
client: &fakeClient{
imageListFunc: func(_ context.Context, _ image.ListOptions) ([]image.Summary, error) {
return []image.Summary{}, errors.New("API error")
},
},
toComplete: "image=",
expected: []string{},
},
{
client: &fakeClient{
networkListFunc: func(_ context.Context, _ network.ListOptions) ([]network.Summary, error) {
return []network.Summary{
*builders.NetworkResource(builders.NetworkResourceName("nw1")),
*builders.NetworkResource(builders.NetworkResourceName("nw2")),
}, nil
},
},
toComplete: "network=",
expected: []string{"network=nw1", "network=nw2"},
},
{
client: &fakeClient{
networkListFunc: func(_ context.Context, _ network.ListOptions) ([]network.Summary, error) {
return nil, errors.New("API error")
},
},
toComplete: "network=",
expected: []string{},
},
{
client: &fakeClient{
nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) {
return []swarm.Node{
*builders.Node(builders.Hostname("n1")),
}, nil
},
},
toComplete: "node=",
expected: []string{"node=n1"},
},
{
client: &fakeClient{
nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) {
return []swarm.Node{}, errors.New("API error")
},
},
toComplete: "node=",
expected: []string{},
},
{
client: &fakeClient{
volumeListFunc: func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) {
return volume.ListResponse{
Volumes: []*volume.Volume{
builders.Volume(builders.VolumeName("v1")),
builders.Volume(builders.VolumeName("v2")),
},
}, nil
},
},
toComplete: "volume=",
expected: []string{"volume=v1", "volume=v2"},
},
{
client: &fakeClient{
volumeListFunc: func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) {
return volume.ListResponse{}, errors.New("API error")
},
},
toComplete: "volume=",
expected: []string{},
},
}
for _, tc := range tests {
cli := test.NewFakeCli(tc.client)
completions, directive := completeEventFilters(cli)(NewEventsCommand(cli), nil, tc.toComplete)
assert.DeepEqual(t, completions, tc.expected)
assert.Equal(t, directive, cobra.ShellCompDirectiveNoFileComp, fmt.Sprintf("wrong directive in completion for '%s'", tc.toComplete))
}
}

View File

@ -50,6 +50,8 @@ func NewEventsCommand(dockerCli command.Cli) *cobra.Command {
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided") flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
flags.StringVar(&options.format, "format", "", flagsHelper.InspectFormatHelp) // using the same flag description as "inspect" commands for now. flags.StringVar(&options.format, "format", "", flagsHelper.InspectFormatHelp) // using the same flag description as "inspect" commands for now.
_ = cmd.RegisterFlagCompletionFunc("filter", completeEventFilters(dockerCli))
return cmd return cmd
} }

View File

@ -53,7 +53,6 @@ func TestEventsFormat(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// Set to UTC timezone as timestamps in output are // Set to UTC timezone as timestamps in output are
// printed in the current timezone // printed in the current timezone

View File

@ -374,7 +374,6 @@ func TestPrettyPrintInfo(t *testing.T) {
expectedError: "errors pretty printing info", expectedError: "errors pretty printing info",
}, },
} { } {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})
err := prettyPrintInfo(cli, tc.dockerInfo) err := prettyPrintInfo(cli, tc.dockerInfo)
@ -452,7 +451,6 @@ func TestFormatInfo(t *testing.T) {
expectedError: `template: :1:2: executing "" at <.badString>: can't evaluate field badString in type system.dockerInfo`, expectedError: `template: :1:2: executing "" at <.badString>: can't evaluate field badString in type system.dockerInfo`,
}, },
} { } {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})
info := dockerInfo{ info := dockerInfo{
@ -518,7 +516,6 @@ func TestNeedsServerInfo(t *testing.T) {
inf := dockerInfo{ClientInfo: &clientInfo{}} inf := dockerInfo{ClientInfo: &clientInfo{}}
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) { t.Run(tc.doc, func(t *testing.T) {
assert.Equal(t, needsServerInfo(tc.template, inf), tc.expected) assert.Equal(t, needsServerInfo(tc.template, inf), tc.expected)
}) })

View File

@ -51,7 +51,7 @@ func NewInspectCommand(dockerCli command.Cli) *cobra.Command {
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error { func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
var elementSearcher inspect.GetRefFunc var elementSearcher inspect.GetRefFunc
switch opts.inspectType { switch opts.inspectType {
case "", "container", "image", "node", "network", "service", "volume", "task", "plugin", "secret": case "", "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume":
elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.inspectType) elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.inspectType)
default: default:
return errors.Errorf("%q is not a valid value for --type", opts.inspectType) return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
@ -114,6 +114,12 @@ func inspectSecret(ctx context.Context, dockerCli command.Cli) inspect.GetRefFun
} }
} }
func inspectConfig(ctx context.Context, dockerCLI command.Cli) inspect.GetRefFunc {
return func(ref string) (any, []byte, error) {
return dockerCLI.Client().ConfigInspectWithRaw(ctx, ref)
}
}
func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc { func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc {
inspectAutodetect := []struct { inspectAutodetect := []struct {
objectType string objectType string
@ -162,6 +168,11 @@ func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeCo
isSwarmObject: true, isSwarmObject: true,
objectInspector: inspectSecret(ctx, dockerCli), objectInspector: inspectSecret(ctx, dockerCli),
}, },
{
objectType: "config",
isSwarmObject: true,
objectInspector: inspectConfig(ctx, dockerCli),
},
} }
// isSwarmManager does an Info API call to verify that the daemon is // isSwarmManager does an Info API call to verify that the daemon is

View File

@ -71,7 +71,6 @@ foobar_bar foo2
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -56,7 +56,6 @@ func TestGetFullCommandName(t *testing.T) {
expected: "root child grandchild", expected: "root child grandchild",
}, },
} { } {
tc := tc
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
t.Parallel() t.Parallel()
actual := getFullCommandName(tc.cmd) actual := getFullCommandName(tc.cmd)
@ -91,7 +90,6 @@ func TestGetCommandName(t *testing.T) {
expected: "child grandchild", expected: "child grandchild",
}, },
} { } {
tc := tc
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
t.Parallel() t.Parallel()
actual := getCommandName(tc.cmd) actual := getCommandName(tc.cmd)
@ -130,7 +128,6 @@ func TestStdioAttributes(t *testing.T) {
}, },
}, },
} { } {
tc := tc
t.Run(tc.test, func(t *testing.T) { t.Run(tc.test, func(t *testing.T) {
t.Parallel() t.Parallel()
cli := &DockerCli{ cli := &DockerCli{
@ -179,7 +176,6 @@ func TestAttributesFromError(t *testing.T) {
}, },
}, },
} { } {
tc := tc
t.Run(tc.testName, func(t *testing.T) { t.Run(tc.testName, func(t *testing.T) {
t.Parallel() t.Parallel()
actual := attributesFromError(tc.err) actual := attributesFromError(tc.err)

View File

@ -127,7 +127,6 @@ tag3 bbbbbbbb
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out
@ -231,7 +230,6 @@ eve foobarbazquxquux, key31, key32
{Name: "eve", Keys: []string{"key31", "key32", "foobarbazquxquux"}}, {Name: "eve", Keys: []string{"key31", "key32", "foobarbazquxquux"}},
} }
for _, tc := range cases { for _, tc := range cases {
tc := tc
t.Run(string(tc.context.Format), func(t *testing.T) { t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer var out bytes.Buffer
tc.context.Output = &out tc.context.Output = &out

View File

@ -116,7 +116,6 @@ var testKeys = map[string][]byte{
func TestLoadKeyFromPath(t *testing.T) { func TestLoadKeyFromPath(t *testing.T) {
skip.If(t, runtime.GOOS == "windows") skip.If(t, runtime.GOOS == "windows")
for keyID, keyBytes := range testKeys { for keyID, keyBytes := range testKeys {
keyID, keyBytes := keyID, keyBytes
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) {
privKeyFilepath := filepath.Join(t.TempDir(), "privkey.pem") privKeyFilepath := filepath.Join(t.TempDir(), "privkey.pem")
assert.NilError(t, os.WriteFile(privKeyFilepath, keyBytes, notary.PrivNoExecPerms)) assert.NilError(t, os.WriteFile(privKeyFilepath, keyBytes, notary.PrivNoExecPerms))
@ -163,7 +162,6 @@ func TestLoadKeyFromPath(t *testing.T) {
func TestLoadKeyTooPermissive(t *testing.T) { func TestLoadKeyTooPermissive(t *testing.T) {
skip.If(t, runtime.GOOS == "windows") skip.If(t, runtime.GOOS == "windows")
for keyID, keyBytes := range testKeys { for keyID, keyBytes := range testKeys {
keyID, keyBytes := keyID, keyBytes
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) {
privKeyDir := t.TempDir() privKeyDir := t.TempDir()
privKeyFilepath := filepath.Join(privKeyDir, "privkey477.pem") privKeyFilepath := filepath.Join(privKeyDir, "privkey477.pem")

View File

@ -30,7 +30,6 @@ func TestTrustSignerRemoveErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := newSignerRemoveCommand( cmd := newSignerRemoveCommand(
test.NewFakeCli(&fakeClient{})) test.NewFakeCli(&fakeClient{}))
@ -66,7 +65,6 @@ func TestTrustSignerRemoveErrors(t *testing.T) {
}, },
} }
for _, tc := range testCasesWithOutput { for _, tc := range testCasesWithOutput {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})
cli.SetNotaryClient(notaryfake.GetOfflineNotaryRepository) cli.SetNotaryClient(notaryfake.GetOfflineNotaryRepository)

View File

@ -52,7 +52,6 @@ func TestVolumePruneErrors(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cmd := NewPruneCommand( cmd := NewPruneCommand(
test.NewFakeCli(&fakeClient{ test.NewFakeCli(&fakeClient{
@ -104,7 +103,6 @@ func TestVolumePruneSuccess(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{volumePruneFunc: tc.volumePruneFunc}) cli := test.NewFakeCli(&fakeClient{volumePruneFunc: tc.volumePruneFunc})
cmd := NewPruneCommand(cli) cmd := NewPruneCommand(cli)
@ -166,7 +164,6 @@ func TestVolumePrunePromptNo(t *testing.T) {
skip.If(t, runtime.GOOS == "windows", "TODO: fix test on windows") skip.If(t, runtime.GOOS == "windows", "TODO: fix test on windows")
for _, input := range []string{"n", "N", "no", "anything", "really"} { for _, input := range []string{"n", "N", "no", "anything", "really"} {
input := input
t.Run(input, func(t *testing.T) { t.Run(input, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
volumePruneFunc: simplePruneFunc, volumePruneFunc: simplePruneFunc,

View File

@ -409,7 +409,6 @@ func TestConvertCredentialSpec(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
namespace := NewNamespace(tc.name) namespace := NewNamespace(tc.name)
swarmSpec, err := convertCredentialSpec(namespace, tc.in, tc.configs) swarmSpec, err := convertCredentialSpec(namespace, tc.in, tc.configs)
@ -691,7 +690,6 @@ func TestConvertServiceCapAddAndCapDrop(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.title, func(t *testing.T) { t.Run(tc.title, func(t *testing.T) {
result, err := Service("1.41", Namespace{name: "foo"}, tc.in, nil, nil, nil, nil) result, err := Service("1.41", Namespace{name: "foo"}, tc.in, nil, nil, nil, nil)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -1626,13 +1626,12 @@ services:
init: &booleanFalse, init: &booleanFalse,
}, },
} }
for _, testcase := range testcases { for _, tc := range testcases {
testcase := testcase t.Run(tc.doc, func(t *testing.T) {
t.Run(testcase.doc, func(t *testing.T) { config, err := loadYAML(tc.yaml)
config, err := loadYAML(testcase.yaml)
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Len(config.Services, 1)) assert.Check(t, is.Len(config.Services, 1))
assert.Check(t, is.DeepEqual(testcase.init, config.Services[0].Init)) assert.Check(t, is.DeepEqual(tc.init, config.Services[0].Init))
}) })
} }
} }

View File

@ -68,7 +68,6 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
}, },
} }
for name, overrideService := range overrideServices { for name, overrideService := range overrideServices {
overrideService := overrideService
if baseService, ok := baseServices[name]; ok { if baseService, ok := baseServices[name]; ok {
if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil { if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil {
return base, errors.Wrapf(err, "cannot merge service %s", name) return base, errors.Wrapf(err, "cannot merge service %s", name)

View File

@ -215,7 +215,6 @@ func TestValidateCredentialSpecs(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.version, func(t *testing.T) { t.Run(tc.version, func(t *testing.T) {
config := dict{ config := dict{
"version": "99.99", "version": "99.99",

View File

@ -277,7 +277,6 @@ func TestExtractVariables(t *testing.T) {
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
actual := ExtractVariables(tc.dict, defaultPattern) actual := ExtractVariables(tc.dict, defaultPattern)
assert.Check(t, is.DeepEqual(actual, tc.expected)) assert.Check(t, is.DeepEqual(actual, tc.expected))

View File

@ -433,7 +433,6 @@ func TestConfigPath(t *testing.T) {
expectedErr: fmt.Sprintf("is outside of root config directory %q", "dummy"), expectedErr: fmt.Sprintf("is outside of root config directory %q", "dummy"),
}, },
} { } {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
SetDir(tc.dir) SetDir(tc.dir)
f, err := Path(tc.path...) f, err := Path(tc.path...)

View File

@ -297,7 +297,6 @@ func TestConvertToHostname(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
tc := tc
t.Run(tc.input, func(t *testing.T) { t.Run(tc.input, func(t *testing.T) {
actual := ConvertToHostname(tc.input) actual := ConvertToHostname(tc.input)
assert.Equal(t, actual, tc.expected) assert.Equal(t, actual, tc.expected)

View File

@ -1,7 +1,8 @@
package oauth package oauth
import ( import (
"github.com/go-jose/go-jose/v3/jwt" "github.com/go-jose/go-jose/v4"
"github.com/go-jose/go-jose/v4/jwt"
) )
// Claims represents standard claims along with some custom ones. // Claims represents standard claims along with some custom ones.
@ -66,8 +67,23 @@ func GetClaims(accessToken string) (claims Claims, err error) {
return return
} }
// allowedSignatureAlgorithms is a list of allowed signature algorithms for JWTs.
// We add all supported algorithms for Auth0, including with higher key lengths.
// See auth0 docs: https://auth0.com/docs/get-started/applications/signing-algorithms
var allowedSignatureAlgorithms = []jose.SignatureAlgorithm{
jose.HS256,
jose.HS384,
jose.HS512,
jose.RS256, // currently used for auth0
jose.RS384,
jose.RS512,
jose.PS256,
jose.PS384,
jose.PS512,
}
// parseSigned parses a JWT and returns the signature object or error. This does // parseSigned parses a JWT and returns the signature object or error. This does
// not verify the validity of the JWT. // not verify the validity of the JWT.
func parseSigned(token string) (*jwt.JSONWebToken, error) { func parseSigned(token string) (*jwt.JSONWebToken, error) {
return jwt.ParseSigned(token) return jwt.ParseSigned(token, allowedSignatureAlgorithms)
} }

View File

@ -81,17 +81,16 @@ func TestStoreSaveAndGet(t *testing.T) {
}, },
} }
for _, testcase := range testcases { for _, tc := range testcases {
testcase := testcase t.Run(tc.manifestRef.String(), func(t *testing.T) {
t.Run(testcase.manifestRef.String(), func(t *testing.T) { actual, err := store.Get(tc.listRef, tc.manifestRef)
actual, err := store.Get(testcase.listRef, testcase.manifestRef) if tc.expectedErr != "" {
if testcase.expectedErr != "" { assert.Error(t, err, tc.expectedErr)
assert.Error(t, err, testcase.expectedErr)
assert.Check(t, IsNotFound(err)) assert.Check(t, IsNotFound(err))
return return
} }
assert.NilError(t, err) assert.NilError(t, err)
assert.DeepEqual(t, testcase.expected, actual, cmpReferenceNamed) assert.DeepEqual(t, tc.expected, actual, cmpReferenceNamed)
}) })
} }
} }

View File

@ -64,14 +64,13 @@ echo '{"SchemaVersion":"0.1.0","Vendor":"Docker Inc.","Version":"v0.6.3","ShortD
) )
defer dir.Remove() defer dir.Remove()
for _, tt := range testcases { for _, tc := range testcases {
tt := tt t.Run(tc.name, func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
ctx2, cancel2 := context.WithCancel(ctx) ctx2, cancel2 := context.WithCancel(ctx)
defer cancel2() defer cancel2()
if tt.builder != "" { if tc.builder != "" {
t.Setenv("BUILDX_BUILDER", tt.builder) t.Setenv("BUILDX_BUILDER", tc.builder)
} }
var b bytes.Buffer var b bytes.Buffer
@ -84,10 +83,10 @@ echo '{"SchemaVersion":"0.1.0","Vendor":"Docker Inc.","Version":"v0.6.3","ShortD
assert.NilError(t, err) assert.NilError(t, err)
assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions())) assert.NilError(t, dockerCli.Initialize(flags.NewClientOptions()))
if tt.context != "" { if tc.context != "" {
if tt.context != command.DefaultContextName { if tc.context != command.DefaultContextName {
assert.NilError(t, dockerCli.ContextStore().CreateOrUpdate(store.Metadata{ assert.NilError(t, dockerCli.ContextStore().CreateOrUpdate(store.Metadata{
Name: tt.context, Name: tc.context,
Endpoints: map[string]any{ Endpoints: map[string]any{
"docker": map[string]any{ "docker": map[string]any{
"host": "unix://" + filepath.Join(t.TempDir(), "docker.sock"), "host": "unix://" + filepath.Join(t.TempDir(), "docker.sock"),
@ -96,12 +95,12 @@ echo '{"SchemaVersion":"0.1.0","Vendor":"Docker Inc.","Version":"v0.6.3","ShortD
})) }))
} }
opts := flags.NewClientOptions() opts := flags.NewClientOptions()
opts.Context = tt.context opts.Context = tc.context
assert.NilError(t, dockerCli.Initialize(opts)) assert.NilError(t, dockerCli.Initialize(opts))
} }
dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()} dockerCli.ConfigFile().CLIPluginsExtraDirs = []string{dir.Path()}
if tt.alias { if tc.alias {
dockerCli.ConfigFile().Aliases = map[string]string{"builder": "buildx"} dockerCli.ConfigFile().Aliases = map[string]string{"builder": "buildx"}
} }
@ -115,8 +114,8 @@ echo '{"SchemaVersion":"0.1.0","Vendor":"Docker Inc.","Version":"v0.6.3","ShortD
args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args) args, os.Args, envs, err = processBuilder(dockerCli, cmd, args, os.Args)
assert.NilError(t, err) assert.NilError(t, err)
assert.DeepEqual(t, []string{builderDefaultPlugin, "build", "."}, args) assert.DeepEqual(t, []string{builderDefaultPlugin, "build", "."}, args)
if tt.expectedEnvs != nil { if tc.expectedEnvs != nil {
assert.DeepEqual(t, tt.expectedEnvs, envs) assert.DeepEqual(t, tc.expectedEnvs, envs)
} else { } else {
assert.Check(t, len(envs) == 0) assert.Check(t, len(envs) == 0)
} }
@ -289,10 +288,9 @@ func TestHasBuilderName(t *testing.T) {
expected: true, expected: true,
}, },
} }
for _, tt := range cases { for _, tc := range cases {
tt := tt t.Run(tc.name, func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tc.expected, hasBuilderName(tc.args, tc.envs))
assert.Equal(t, tt.expected, hasBuilderName(tt.args, tt.envs))
}) })
} }
} }

Some files were not shown because too many files have changed in this diff Show More