diff --git a/cmd/compose/images.go b/cmd/compose/images.go index 5544204c893..4f305e49195 100644 --- a/cmd/compose/images.go +++ b/cmd/compose/images.go @@ -101,6 +101,10 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service, // Convert map to slice var imageList []img for ctr, i := range images { + lastTagTime := i.LastTagTime + if lastTagTime.IsZero() { + lastTagTime = i.Created + } imageList = append(imageList, img{ ContainerName: ctr, ID: i.ID, @@ -108,7 +112,7 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service, Tag: i.Tag, Platform: platforms.Format(i.Platform), Size: i.Size, - LastTagTime: i.LastTagTime, + LastTagTime: lastTagTime, }) } json, err := formatter.ToJSON(imageList, "", "") diff --git a/pkg/api/api.go b/pkg/api/api.go index a48b5ab5fa4..51140757a68 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -558,6 +558,7 @@ type ImageSummary struct { Tag string Platform platforms.Platform Size int64 + Created time.Time LastTagTime time.Time } diff --git a/pkg/compose/images.go b/pkg/compose/images.go index a91d6159f4b..d49e92c6584 100644 --- a/pkg/compose/images.go +++ b/pkg/compose/images.go @@ -22,6 +22,7 @@ import ( "slices" "strings" "sync" + "time" "github.com/containerd/errdefs" "github.com/containerd/platforms" @@ -90,6 +91,11 @@ func (s *composeService) Images(ctx context.Context, projectName string, options } } + created, err := time.Parse(time.RFC3339Nano, image.Created) + if err != nil { + return err + } + mux.Lock() defer mux.Unlock() summary[getCanonicalContainerName(c)] = api.ImageSummary{ @@ -103,6 +109,7 @@ func (s *composeService) Images(ctx context.Context, projectName string, options Variant: image.Variant, }, Size: image.Size, + Created: created, LastTagTime: image.Metadata.LastTagTime, } return nil diff --git a/pkg/compose/images_test.go b/pkg/compose/images_test.go index a7a1d5e9a36..85a2b577007 100644 --- a/pkg/compose/images_test.go +++ b/pkg/compose/images_test.go @@ -20,6 +20,7 @@ import ( "context" "strings" "testing" + "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -44,8 +45,12 @@ func TestImages(t *testing.T) { args := filters.NewArgs(projectFilter(strings.ToLower(testProject))) listOpts := container.ListOptions{All: true, Filters: args} api.EXPECT().ServerVersion(gomock.Any()).Return(types.Version{APIVersion: "1.96"}, nil).AnyTimes() - image1 := imageInspect("image1", "foo:1", 12345) - image2 := imageInspect("image2", "bar:2", 67890) + timeStr1 := "2025-06-06T06:06:06.000000000Z" + created1, _ := time.Parse(time.RFC3339Nano, timeStr1) + timeStr2 := "2025-03-03T03:03:03.000000000Z" + created2, _ := time.Parse(time.RFC3339Nano, timeStr2) + image1 := imageInspect("image1", "foo:1", 12345, timeStr1) + image2 := imageInspect("image2", "bar:2", 67890, timeStr2) api.EXPECT().ImageInspect(anyCancellableContext(), "foo:1").Return(image1, nil).MaxTimes(2) api.EXPECT().ImageInspect(anyCancellableContext(), "bar:2").Return(image2, nil) c1 := containerDetail("service1", "123", "running", "foo:1") @@ -62,32 +67,36 @@ func TestImages(t *testing.T) { Repository: "foo", Tag: "1", Size: 12345, + Created: created1, }, "456": { ID: "image2", Repository: "bar", Tag: "2", Size: 67890, + Created: created2, }, "789": { ID: "image1", Repository: "foo", Tag: "1", Size: 12345, + Created: created1, }, } assert.NilError(t, err) assert.DeepEqual(t, images, expected) } -func imageInspect(id string, imageReference string, size int64) image.InspectResponse { +func imageInspect(id string, imageReference string, size int64, created string) image.InspectResponse { return image.InspectResponse{ ID: id, RepoTags: []string{ "someRepo:someTag", imageReference, }, - Size: size, + Size: size, + Created: created, } }