@@ -21,7 +21,9 @@ import (
2121 "errors"
2222 "fmt"
2323 "regexp"
24+ "slices"
2425 "sort"
26+ "strings"
2527 "time"
2628
2729 "github.com/google/go-containerregistry/pkg/name"
@@ -192,6 +194,7 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
192194 oldObj := obj .DeepCopy ()
193195
194196 var foundTags int
197+ var tagsChecksum string
195198 // Store a message about current reconciliation and next scan.
196199 var nextScanMsg string
197200 // Set a default next scan time before processing the object.
@@ -206,7 +209,7 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
206209 return true
207210 }
208211
209- readyMsg := fmt .Sprintf ("successful scan: found %d tags" , foundTags )
212+ readyMsg := fmt .Sprintf ("successful scan: found %d tags with checksum %s " , foundTags , tagsChecksum )
210213 rs := reconcile .NewResultFinalizer (isSuccess , readyMsg )
211214 retErr = rs .Finalize (obj , result , retErr )
212215
@@ -290,25 +293,27 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
290293 // Scan the repository if it's scan time. No scan is a no-op reconciliation.
291294 // The next scan time is not reset in case of no-op reconciliation.
292295 if ok {
293- reconcile .ProgressiveStatus (false , obj , meta .ProgressingReason , "scanning: %s" , reasonMsg )
296+ drift := reasonMsg == scanReasonEmptyDatabase
297+ reconcile .ProgressiveStatus (drift , obj , meta .ProgressingReason , "scanning: %s" , reasonMsg )
294298 if err := sp .Patch (ctx , obj , r .patchOptions ... ); err != nil {
295299 result , retErr = ctrl.Result {}, err
296300 return
297301 }
298302
299- tags , err := r .scan (ctx , obj , ref , opts )
303+ tags , checksum , err := r .scan (ctx , obj , ref , opts )
300304 if err != nil {
301305 e := fmt .Errorf ("scan failed: %w" , err )
302306 conditions .MarkFalse (obj , meta .ReadyCondition , imagev1 .ReadOperationFailedReason , "%s" , e )
303307 result , retErr = ctrl.Result {}, e
304308 return
305309 }
306310 foundTags = tags
311+ tagsChecksum = checksum
307312
308313 nextScanMsg = fmt .Sprintf ("next scan in %s" , when .String ())
309314 // Check if new tags were found.
310- if oldObj . Status . LastScanResult != nil &&
311- oldObj . Status . LastScanResult . TagCount == foundTags {
315+ s := strings . Split ( conditions . GetMessage ( oldObj , meta . ReadyCondition ), " tags with checksum " )
316+ if len ( s ) == 2 && s [ 1 ] == checksum {
312317 nextScanMsg = "no new tags found, " + nextScanMsg
313318 } else {
314319 // When new tags are found, this message will be suppressed by
@@ -405,7 +410,8 @@ func (r *ImageRepositoryReconciler) shouldScan(obj imagev1.ImageRepository, now
405410
406411// scan performs repository scanning and writes the scanned result in the
407412// internal database and populates the status of the ImageRepository.
408- func (r * ImageRepositoryReconciler ) scan (ctx context.Context , obj * imagev1.ImageRepository , ref name.Reference , options []remote.Option ) (int , error ) {
413+ // It returns the number of tags found, the checksum of the tags, and an error.
414+ func (r * ImageRepositoryReconciler ) scan (ctx context.Context , obj * imagev1.ImageRepository , ref name.Reference , options []remote.Option ) (int , string , error ) {
409415 timeout := obj .GetTimeout ()
410416 ctx , cancel := context .WithTimeout (ctx , timeout )
411417 defer cancel ()
@@ -414,17 +420,20 @@ func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.Image
414420
415421 tags , err := remote .List (ref .Context (), options ... )
416422 if err != nil {
417- return 0 , err
423+ return 0 , "" , err
418424 }
419425
420426 filteredTags , err := filterOutTags (tags , obj .GetExclusionList ())
421427 if err != nil {
422- return 0 , err
428+ return 0 , "" , err
423429 }
424430
431+ slices .Sort (filteredTags )
432+
425433 canonicalName := ref .Context ().String ()
426- if err := r .Database .SetTags (canonicalName , filteredTags ); err != nil {
427- return 0 , fmt .Errorf ("failed to set tags for %q: %w" , canonicalName , err )
434+ checksum , err := r .Database .SetTags (canonicalName , filteredTags )
435+ if err != nil {
436+ return 0 , "" , fmt .Errorf ("failed to set tags for %q: %w" , canonicalName , err )
428437 }
429438
430439 scanTime := metav1 .Now ()
@@ -441,7 +450,7 @@ func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.Image
441450 obj .Status .SetLastHandledReconcileRequest (token )
442451 }
443452
444- return len (filteredTags ), nil
453+ return len (filteredTags ), checksum , nil
445454}
446455
447456// reconcileDelete handles the deletion of the object.
0 commit comments