Fix: use image created time when last tag time is not present

Signed-off-by: Kian Eliasi <kian.elbo@gmail.com>
This commit is contained in:
Kian Eliasi 2025-08-25 21:50:23 +03:30 committed by Nicolas De loof
parent 73e593e69a
commit 6078b4d99d
4 changed files with 22 additions and 5 deletions

View File

@ -103,7 +103,7 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
for ctr, i := range images { for ctr, i := range images {
lastTagTime := i.LastTagTime lastTagTime := i.LastTagTime
if lastTagTime.IsZero() { if lastTagTime.IsZero() {
lastTagTime = time.Now() lastTagTime = i.Created
} }
imageList = append(imageList, img{ imageList = append(imageList, img{
ContainerName: ctr, ContainerName: ctr,

View File

@ -558,6 +558,7 @@ type ImageSummary struct {
Tag string Tag string
Platform platforms.Platform Platform platforms.Platform
Size int64 Size int64
Created time.Time
LastTagTime time.Time LastTagTime time.Time
} }

View File

@ -22,6 +22,7 @@ import (
"slices" "slices"
"strings" "strings"
"sync" "sync"
"time"
"github.com/containerd/errdefs" "github.com/containerd/errdefs"
"github.com/containerd/platforms" "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() mux.Lock()
defer mux.Unlock() defer mux.Unlock()
summary[getCanonicalContainerName(c)] = api.ImageSummary{ summary[getCanonicalContainerName(c)] = api.ImageSummary{
@ -103,6 +109,7 @@ func (s *composeService) Images(ctx context.Context, projectName string, options
Variant: image.Variant, Variant: image.Variant,
}, },
Size: image.Size, Size: image.Size,
Created: created,
LastTagTime: image.Metadata.LastTagTime, LastTagTime: image.Metadata.LastTagTime,
} }
return nil return nil

View File

@ -20,6 +20,7 @@ import (
"context" "context"
"strings" "strings"
"testing" "testing"
"time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@ -44,8 +45,12 @@ func TestImages(t *testing.T) {
args := filters.NewArgs(projectFilter(strings.ToLower(testProject))) args := filters.NewArgs(projectFilter(strings.ToLower(testProject)))
listOpts := container.ListOptions{All: true, Filters: args} listOpts := container.ListOptions{All: true, Filters: args}
api.EXPECT().ServerVersion(gomock.Any()).Return(types.Version{APIVersion: "1.96"}, nil).AnyTimes() api.EXPECT().ServerVersion(gomock.Any()).Return(types.Version{APIVersion: "1.96"}, nil).AnyTimes()
image1 := imageInspect("image1", "foo:1", 12345) timeStr1 := "2025-06-06T06:06:06.000000000Z"
image2 := imageInspect("image2", "bar:2", 67890) 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(), "foo:1").Return(image1, nil).MaxTimes(2)
api.EXPECT().ImageInspect(anyCancellableContext(), "bar:2").Return(image2, nil) api.EXPECT().ImageInspect(anyCancellableContext(), "bar:2").Return(image2, nil)
c1 := containerDetail("service1", "123", "running", "foo:1") c1 := containerDetail("service1", "123", "running", "foo:1")
@ -62,32 +67,36 @@ func TestImages(t *testing.T) {
Repository: "foo", Repository: "foo",
Tag: "1", Tag: "1",
Size: 12345, Size: 12345,
Created: created1,
}, },
"456": { "456": {
ID: "image2", ID: "image2",
Repository: "bar", Repository: "bar",
Tag: "2", Tag: "2",
Size: 67890, Size: 67890,
Created: created2,
}, },
"789": { "789": {
ID: "image1", ID: "image1",
Repository: "foo", Repository: "foo",
Tag: "1", Tag: "1",
Size: 12345, Size: 12345,
Created: created1,
}, },
} }
assert.NilError(t, err) assert.NilError(t, err)
assert.DeepEqual(t, images, expected) 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{ return image.InspectResponse{
ID: id, ID: id,
RepoTags: []string{ RepoTags: []string{
"someRepo:someTag", "someRepo:someTag",
imageReference, imageReference,
}, },
Size: size, Size: size,
Created: created,
} }
} }