diff --git a/internal/tracker/tracker.go b/internal/tracker/tracker.go index c8450fefb..75aac30e8 100644 --- a/internal/tracker/tracker.go +++ b/internal/tracker/tracker.go @@ -204,36 +204,48 @@ func (t *Tracker) filterBundles(prune bool) { } // filterRecords reduces the list of records by removing superfluous entries. -// It removes records that have the same Repository and Digest. If prune is +// It removes records that have the same Repository Digest, and Tag. If prune is // true, it skips any record that is no longer acceptable. Any record with an // EffectiveOn date in the future, and the record with the most recent // EffectiveOn date *not* in the future are considered acceptable. func filterRecords(records []bundleRecord, prune bool) []bundleRecord { now := time.Now().UTC() + // lastDigestForTag tracks the latest digest seen for each tag. + lastDigestForTag := map[string]string{} unique := make([]bundleRecord, 0, len(records)) - last_index := len(records) - 1 - for i := last_index; i >= 0; i-- { - r := records[i] + for i := len(records) - 1; i >= 0; i-- { // NOTE: Newly added records will have a repository, but existing ones // will not. This is expected because the output does not persist the // repository for each record. Instead, the repository is the attribute // which references the list of records. - if i < last_index { - previous := records[i+1] - if previous.Digest == r.Digest { - continue - } + r := records[i] + + if digest, ok := lastDigestForTag[r.Tag]; ok && digest == r.Digest { + continue } + lastDigestForTag[r.Tag] = r.Digest + unique = append([]bundleRecord{r}, unique...) } - relevant := make([]bundleRecord, 0, len(unique)) - for _, r := range unique { - relevant = append(relevant, r) - if prune && now.After(r.EffectiveOn) { - break + var relevant []bundleRecord + if prune { + // tagsToSkip tracks when records for a certain tag should start to be pruned. + tagsToSkip := map[string]bool{} + for _, r := range unique { + if tagsToSkip[r.Tag] { + continue + } + relevant = append(relevant, r) + if !tagsToSkip[r.Tag] { + if now.After(r.EffectiveOn) { + tagsToSkip[r.Tag] = true + } + } } + } else { + relevant = unique } filteredCount := len(records) - len(relevant) diff --git a/internal/tracker/tracker_test.go b/internal/tracker/tracker_test.go index 21f77f11a..83e8425a3 100644 --- a/internal/tracker/tracker_test.go +++ b/internal/tracker/tracker_test.go @@ -217,7 +217,7 @@ func TestTrack(t *testing.T) { registry.com/one: - digest: ` + sampleHashOne.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.9" + tag: "1.0" `)), output: hd.Doc(` --- @@ -225,7 +225,7 @@ func TestTrack(t *testing.T) { registry.com/one: - digest: ` + sampleHashOne.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.9" + tag: "1.0" `), }, { @@ -240,18 +240,26 @@ func TestTrack(t *testing.T) { registry.com/mixed: - digest: ` + sampleHashThree.String() + ` effective_on: "` + yesterday + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + yesterday + `" - tag: "0.2" + tag: "1.0" + # Unrelated tag should be ignored. + - digest: sha256:abc + effective_on: "` + yesterday + `" + tag: "0.9" task-bundles: registry.com/mixed: - digest: ` + sampleHashThree.String() + ` effective_on: "` + yesterday + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + yesterday + `" - tag: "0.2" + tag: "1.0" + # Unrelated tag should be ignored. + - digest: sha256:abc + effective_on: "` + yesterday + `" + tag: "0.9" `)), output: hd.Doc(` --- @@ -262,7 +270,10 @@ func TestTrack(t *testing.T) { tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + yesterday + `" - tag: "0.3" + tag: "1.0" + - digest: sha256:abc + effective_on: "` + yesterday + `" + tag: "0.9" task-bundles: registry.com/mixed: - digest: ` + sampleHashOne.String() + ` @@ -270,7 +281,10 @@ func TestTrack(t *testing.T) { tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + yesterday + `" - tag: "0.3" + tag: "1.0" + - digest: sha256:abc + effective_on: "` + yesterday + `" + tag: "0.9" `), }, { @@ -348,30 +362,30 @@ func TestTrack(t *testing.T) { registry.com/mixed: - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" task-bundles: registry.com/mixed: - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" `)), output: hd.Doc(` --- @@ -382,16 +396,16 @@ func TestTrack(t *testing.T) { tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" task-bundles: registry.com/mixed: - digest: ` + sampleHashOne.String() + ` @@ -399,16 +413,16 @@ func TestTrack(t *testing.T) { tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" - digest: ` + sampleHashThree.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.3" + tag: "1.0" - digest: ` + sampleHashTwo.String() + ` effective_on: "` + expectedEffectiveOn + `" - tag: "0.2" + tag: "1.0" `), }, { @@ -436,7 +450,7 @@ func TestTrack(t *testing.T) { }, } - for _, tt := range tests[len(tests)-1:] { + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.WithValue(context.Background(), image.RemoteHead, head)