2024-06-18 05:59:39 -04:00
|
|
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
2024-06-18 06:07:25 -04:00
|
|
|
//go:build go1.21
|
2024-06-18 05:59:39 -04:00
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
package image
|
|
|
|
|
|
|
|
import (
|
2018-05-03 21:02:44 -04:00
|
|
|
"context"
|
2024-06-10 13:17:50 -04:00
|
|
|
"encoding/json"
|
2018-07-18 15:29:56 -04:00
|
|
|
"fmt"
|
2022-02-25 07:10:34 -05:00
|
|
|
"io"
|
2024-07-09 09:35:36 -04:00
|
|
|
"strings"
|
2016-09-08 13:11:39 -04:00
|
|
|
|
2024-04-03 09:00:29 -04:00
|
|
|
"github.com/containerd/platforms"
|
2023-08-30 18:36:58 -04:00
|
|
|
"github.com/distribution/reference"
|
2017-04-17 18:07:56 -04:00
|
|
|
"github.com/docker/cli/cli"
|
|
|
|
"github.com/docker/cli/cli/command"
|
2022-03-30 09:27:25 -04:00
|
|
|
"github.com/docker/cli/cli/command/completion"
|
2020-01-24 07:53:24 -05:00
|
|
|
"github.com/docker/cli/cli/streams"
|
2024-06-10 13:17:50 -04:00
|
|
|
"github.com/docker/docker/api/types/auxprogress"
|
2024-01-24 08:32:07 -05:00
|
|
|
"github.com/docker/docker/api/types/image"
|
2023-04-11 12:16:30 -04:00
|
|
|
registrytypes "github.com/docker/docker/api/types/registry"
|
2016-09-08 13:11:39 -04:00
|
|
|
"github.com/docker/docker/pkg/jsonmessage"
|
|
|
|
"github.com/docker/docker/registry"
|
2024-06-10 13:17:50 -04:00
|
|
|
"github.com/morikuni/aec"
|
2024-04-03 09:00:29 -04:00
|
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
"github.com/pkg/errors"
|
2016-09-08 13:11:39 -04:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2018-03-08 08:35:17 -05:00
|
|
|
type pushOptions struct {
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
all bool
|
2018-03-08 08:35:17 -05:00
|
|
|
remote string
|
|
|
|
untrusted bool
|
2018-07-18 15:29:56 -04:00
|
|
|
quiet bool
|
2024-04-03 09:00:29 -04:00
|
|
|
platform string
|
2018-03-08 08:35:17 -05:00
|
|
|
}
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
// NewPushCommand creates a new `docker push` command
|
2017-03-30 20:21:14 -04:00
|
|
|
func NewPushCommand(dockerCli command.Cli) *cobra.Command {
|
2018-03-08 08:35:17 -05:00
|
|
|
var opts pushOptions
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "push [OPTIONS] NAME[:TAG]",
|
2022-03-29 18:11:09 -04:00
|
|
|
Short: "Upload an image to a registry",
|
2016-09-08 13:11:39 -04:00
|
|
|
Args: cli.ExactArgs(1),
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
2018-03-08 08:35:17 -05:00
|
|
|
opts.remote = args[0]
|
2023-09-09 18:27:44 -04:00
|
|
|
return RunPush(cmd.Context(), dockerCli, opts)
|
2016-09-08 13:11:39 -04:00
|
|
|
},
|
2022-03-30 03:37:08 -04:00
|
|
|
Annotations: map[string]string{
|
|
|
|
"category-top": "6",
|
cli: use custom annotation for aliases
Cobra allows for aliases to be defined for a command, but only allows these
to be defined at the same level (for example, `docker image ls` as alias for
`docker image list`). Our CLI has some commands that are available both as a
top-level shorthand as well as `docker <object> <verb>` subcommands. For example,
`docker ps` is a shorthand for `docker container ps` / `docker container ls`.
This patch introduces a custom "aliases" annotation that can be used to print
all available aliases for a command. While this requires these aliases to be
defined manually, in practice the list of aliases rarely changes, so maintenance
should be minimal.
As a convention, we could consider the first command in this list to be the
canonical command, so that we can use this information to add redirects in
our documentation in future.
Before this patch:
docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
...
With this patch:
docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Aliases:
docker image ls, docker image list, docker images
Options:
-a, --all Show all images (default hides intermediate images)
...
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-06-28 04:52:25 -04:00
|
|
|
"aliases": "docker image push, docker push",
|
2022-03-30 03:37:08 -04:00
|
|
|
},
|
2022-03-30 09:27:25 -04:00
|
|
|
ValidArgsFunction: completion.ImageNames(dockerCli),
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
flags := cmd.Flags()
|
2022-03-10 12:39:06 -05:00
|
|
|
flags.BoolVarP(&opts.all, "all-tags", "a", false, "Push all tags of an image to the repository")
|
2018-07-18 15:29:56 -04:00
|
|
|
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output")
|
2018-03-08 14:56:56 -05:00
|
|
|
command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
|
2024-07-08 08:40:51 -04:00
|
|
|
|
|
|
|
// Don't default to DOCKER_DEFAULT_PLATFORM env variable, always default to
|
|
|
|
// pushing the image as-is. This also avoids forcing the platform selection
|
|
|
|
// on older APIs which don't support it.
|
|
|
|
flags.StringVar(&opts.platform, "platform", "",
|
2024-04-03 09:00:29 -04:00
|
|
|
`Push a platform-specific manifest as a single-platform image to the registry.
|
2024-07-09 09:35:36 -04:00
|
|
|
Image index won't be pushed, meaning that other manifests, including attestations won't be preserved.
|
2024-04-03 09:00:29 -04:00
|
|
|
'os[/arch[/variant]]': Explicit platform (eg. linux/amd64)`)
|
|
|
|
flags.SetAnnotation("platform", "version", []string{"1.46"})
|
2016-09-08 13:11:39 -04:00
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
2018-06-14 09:48:21 -04:00
|
|
|
// RunPush performs a push against the engine based on the specified options
|
2024-06-10 13:17:50 -04:00
|
|
|
//
|
|
|
|
//nolint:gocyclo
|
2023-09-09 18:27:44 -04:00
|
|
|
func RunPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error {
|
2024-04-03 09:00:29 -04:00
|
|
|
var platform *ocispec.Platform
|
|
|
|
if opts.platform != "" {
|
|
|
|
p, err := platforms.Parse(opts.platform)
|
|
|
|
if err != nil {
|
|
|
|
_, _ = fmt.Fprintf(dockerCli.Err(), "Invalid platform %s", opts.platform)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
platform = &p
|
|
|
|
|
2024-07-09 09:35:36 -04:00
|
|
|
printNote(dockerCli, `Using --platform pushes only the specified platform manifest of a multi-platform image index.
|
|
|
|
Other components, like attestations, will not be included.
|
|
|
|
To push the complete multi-platform image, remove the --platform flag.
|
2024-06-10 13:17:50 -04:00
|
|
|
`)
|
2024-04-03 09:00:29 -04:00
|
|
|
}
|
|
|
|
|
2018-03-08 08:35:17 -05:00
|
|
|
ref, err := reference.ParseNormalizedNamed(opts.remote)
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
switch {
|
|
|
|
case err != nil:
|
2016-09-08 13:11:39 -04:00
|
|
|
return err
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
case opts.all && !reference.IsNameOnly(ref):
|
|
|
|
return errors.New("tag can't be used with --all-tags/-a")
|
|
|
|
case !opts.all && reference.IsNameOnly(ref):
|
|
|
|
ref = reference.TagNameOnly(ref)
|
|
|
|
if tagged, ok := ref.(reference.Tagged); ok && !opts.quiet {
|
|
|
|
_, _ = fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag())
|
|
|
|
}
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve the Repository name from fqn to RepositoryInfo
|
|
|
|
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve the Auth config relevant for this server
|
2023-07-10 11:24:07 -04:00
|
|
|
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
|
2023-04-11 12:16:30 -04:00
|
|
|
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-09-09 15:38:00 -04:00
|
|
|
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
|
2024-01-24 08:32:07 -05:00
|
|
|
options := image.PushOptions{
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
All: opts.all,
|
|
|
|
RegistryAuth: encodedAuth,
|
|
|
|
PrivilegeFunc: requestPrivilege,
|
2024-04-03 09:00:29 -04:00
|
|
|
Platform: platform,
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
responseBody, err := dockerCli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
|
2016-09-08 13:11:39 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-06-10 13:17:50 -04:00
|
|
|
defer func() {
|
|
|
|
for _, note := range notes {
|
|
|
|
fmt.Fprintln(dockerCli.Err(), "")
|
|
|
|
printNote(dockerCli, note)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
defer responseBody.Close()
|
implement docker push -a/--all-tags
The `docker push` command up until [v0.9.1](https://github.com/moby/moby/blob/v0.9.1/api/client.go#L998)
always pushed all tags of a given image, so `docker push foo/bar` would push (e.g.)
all of `foo/bar:latest`, `foo:/bar:v1`, `foo/bar:v1.0.0`.
Pushing all tags of an image was not desirable in many case, so docker v0.10.0
enhanced `docker push` to optionally specify a tag to push (`docker push foo/bar:v1`)
(see https://github.com/moby/moby/issues/3411 and the pull request that implemented
this: https://github.com/moby/moby/pull/4948).
This behavior exists up until today, and is confusing, because unlike other commands,
`docker push` does not default to use the `:latest` tag when omitted, but instead
makes it push "all tags of the image"
For example, in the following situation;
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
```
Running `docker push thajeztah/myimage` seemingly does the expected behavior (it
pushes `thajeztah/myimage:latest` to Docker Hub), however, it does not so for the
reason expected (`:latest` being the default tag), but because `:latest` happens
to be the only tag present for the `thajeztah/myimage` image.
If another tag exists for the image:
```
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thajeztah/myimage latest b534869c81f0 41 hours ago 1.22MB
thajeztah/myimage v1.0.0 b534869c81f0 41 hours ago 1.22MB
```
Running the same command (`docker push thajeztah/myimage`) will push _both_ images
to Docker Hub.
> Note that the behavior described above is currently not (clearly) documented;
> the `docker push` reference documentation (https://docs.docker.com/engine/reference/commandline/push/)
does not mention that omitting the tag will push all tags
This patch changes the default behavior, and if no tag is specified, `:latest` is
assumed. To push _all_ tags, a new flag (`-a` / `--all-tags`) is added, similar
to the flag that's present on `docker pull`.
With this change:
- `docker push myname/myimage` will be the equivalent of `docker push myname/myimage:latest`
- to push all images, the user needs to set a flag (`--all-tags`), so `docker push --all-tags myname/myimage:latest`
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-09 08:48:42 -05:00
|
|
|
if !opts.untrusted {
|
|
|
|
// TODO PushTrustedReference currently doesn't respect `--quiet`
|
|
|
|
return PushTrustedReference(dockerCli, repoInfo, ref, authConfig, responseBody)
|
|
|
|
}
|
|
|
|
|
2020-01-24 07:53:24 -05:00
|
|
|
if opts.quiet {
|
2024-06-10 13:17:50 -04:00
|
|
|
err = jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(io.Discard), handleAux(dockerCli))
|
2020-01-24 07:53:24 -05:00
|
|
|
if err == nil {
|
|
|
|
fmt.Fprintln(dockerCli.Out(), ref.String())
|
|
|
|
}
|
|
|
|
return err
|
2018-07-18 15:29:56 -04:00
|
|
|
}
|
2024-06-10 13:17:50 -04:00
|
|
|
return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), handleAux(dockerCli))
|
|
|
|
}
|
|
|
|
|
|
|
|
var notes []string
|
|
|
|
|
|
|
|
func handleAux(dockerCli command.Cli) func(jm jsonmessage.JSONMessage) {
|
|
|
|
return func(jm jsonmessage.JSONMessage) {
|
|
|
|
b := []byte(*jm.Aux)
|
|
|
|
|
|
|
|
var stripped auxprogress.ManifestPushedInsteadOfIndex
|
|
|
|
err := json.Unmarshal(b, &stripped)
|
|
|
|
if err == nil && stripped.ManifestPushedInsteadOfIndex {
|
|
|
|
note := fmt.Sprintf("Not all multiplatform-content is present and only the available single-platform image was pushed\n%s -> %s",
|
|
|
|
aec.RedF.Apply(stripped.OriginalIndex.Digest.String()),
|
|
|
|
aec.GreenF.Apply(stripped.SelectedManifest.Digest.String()),
|
|
|
|
)
|
|
|
|
notes = append(notes, note)
|
|
|
|
}
|
|
|
|
|
|
|
|
var missing auxprogress.ContentMissing
|
|
|
|
err = json.Unmarshal(b, &missing)
|
|
|
|
if err == nil && missing.ContentMissing {
|
|
|
|
note := `You're trying to push a manifest list/index which
|
|
|
|
references multiple platform specific manifests, but not all of them are available locally
|
|
|
|
or available to the remote repository.
|
|
|
|
|
|
|
|
Make sure you have all the referenced content and try again.
|
|
|
|
|
|
|
|
You can also push only a single platform specific manifest directly by specifying the platform you want to push with the --platform flag.`
|
|
|
|
notes = append(notes, note)
|
|
|
|
}
|
|
|
|
}
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
2024-04-03 09:00:29 -04:00
|
|
|
|
|
|
|
func printNote(dockerCli command.Cli, format string, args ...any) {
|
2024-06-11 10:49:25 -04:00
|
|
|
if dockerCli.Err().IsTerminal() {
|
2024-07-09 09:35:36 -04:00
|
|
|
format = strings.ReplaceAll(format, "--platform", aec.Bold.Apply("--platform"))
|
|
|
|
}
|
|
|
|
|
|
|
|
header := " Info -> "
|
|
|
|
padding := len(header)
|
|
|
|
if dockerCli.Err().IsTerminal() {
|
|
|
|
padding = len("i Info > ")
|
|
|
|
header = aec.Bold.Apply(aec.LightCyanB.Apply(aec.BlackF.Apply("i")) + " " + aec.LightCyanF.Apply("Info → "))
|
|
|
|
}
|
|
|
|
|
|
|
|
_, _ = fmt.Fprint(dockerCli.Err(), header)
|
|
|
|
s := fmt.Sprintf(format, args...)
|
|
|
|
for idx, line := range strings.Split(s, "\n") {
|
|
|
|
if idx > 0 {
|
|
|
|
_, _ = fmt.Fprint(dockerCli.Err(), strings.Repeat(" ", padding))
|
|
|
|
}
|
|
|
|
_, _ = fmt.Fprintln(dockerCli.Err(), aec.Italic.Apply(line))
|
2024-04-03 09:00:29 -04:00
|
|
|
}
|
|
|
|
}
|