sort image tags newest first

AuthorKonata <konata@posteo.jp>
Date
Commit17bebd9e5b08ac08cbd72f7bb5eafc1b8f412c81
Parent437cbd6
2 files changed, 16 insertions(+), 2 deletions(-)
▾Minternal/db/registry.go
@@ -149,10 +149,12 @@ type ImageTag struct {
UpdatedAt string
}
// ListImageTags returns every tag of the repo, grouped by image path.
// ListImageTags returns every tag of the repo, grouped by image path, the
// most recently pushed tag first.
func (d *DB) ListImageTags(ctx context.Context, repoID int64) ([]ImageTag, error) {
rows, err := d.QueryContext(ctx,
`SELECT image, tag, digest, updated_at FROM registry_tags WHERE repo_id = ? ORDER BY image, tag`, repoID)
`SELECT image, tag, digest, updated_at FROM registry_tags WHERE repo_id = ?
ORDER BY image, updated_at DESC, tag`, repoID)
if err != nil {
return nil, err
}
▾Minternal/web/e2e/images_test.go
@@ -42,6 +42,18 @@ func TestImagesTab(t *testing.T) {
}
})
t.Run("tags are listed newest first", func(t *testing.T) {
for tag, at := range map[string]string{"v1": "2026-01-01T00:00:00Z", "v2": "2026-02-01T00:00:00Z"} {
if _, err := e.DB.Exec(`UPDATE registry_tags SET updated_at = ? WHERE tag = ? AND image = ''`, at, tag); err != nil {
t.Fatal(err)
}
}
tags := admin.get("/img-repo/images").Texts(".image-tag .badge")
if want := []string{"v2", "v1", "latest"}; !eqStrings(tags, want) {
t.Errorf("tags = %v, want %v", tags, want)
}
})
t.Run("access follows REGISTRY_PULL", func(t *testing.T) {
alice.get("/img-repo/images").mustStatus(200)
if e.anon().get("/img-repo/images").Code != 403 {