From 7a09e3e08df804a08a4020e0bc85a953e0d7a27d Mon Sep 17 00:00:00 2001 From: Deluan Date: Fri, 14 Aug 2026 15:22:30 -0400 Subject: [PATCH] fix(cli): print the absent artwork source under the name --source accepts `artwork explain` rendered the stored empty source as "(absent)", while `artwork reprocess --source` only accepts "absent", so pasting what explain printed straight back into reprocess was rejected as an unknown source. --- cmd/artwork.go | 2 +- cmd/artwork_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cmd/artwork.go b/cmd/artwork.go index 1b1a8ccba..f5dee3cbf 100644 --- a/cmd/artwork.go +++ b/cmd/artwork.go @@ -560,7 +560,7 @@ func formatExplain(rep explainReport) string { if rep.stored == nil { fmt.Fprintln(w, " (no artwork state recorded)") } else { - fmt.Fprintf(w, " Source:\t%s\n", cmp.Or(rep.stored.Source, "(absent)")) + fmt.Fprintf(w, " Source:\t%s\n", displaySource(rep.stored.Source)) fmt.Fprintf(w, " Hash:\t%s\n", cmp.Or(rep.stored.Hash, "(absent)")) if rep.stored.SourcePath != "" { fmt.Fprintf(w, " Source path:\t%s\n", rep.stored.SourcePath) diff --git a/cmd/artwork_test.go b/cmd/artwork_test.go index 16407bbb4..5bce316e0 100644 --- a/cmd/artwork_test.go +++ b/cmd/artwork_test.go @@ -245,6 +245,38 @@ var _ = Describe("reprocessSelectsAll", func() { }) }) +var _ = Describe("explain/reprocess source round trip", func() { + ctx := context.Background() + + // storedSource reads back the Source line explain printed, as an operator would copy it. + storedSource := func(out string) string { + GinkgoHelper() + for line := range strings.SplitSeq(out, "\n") { + if after, ok := strings.CutPrefix(strings.TrimSpace(line), "Source:"); ok { + return strings.TrimSpace(after) + } + } + Fail("explain printed no Source line") + return "" + } + + It("names the absent state as reprocess --source accepts it", func() { + ds := &tests.MockDataStore{} + art := ds.Artwork(ctx).(*tests.MockArtworkRepo) + Expect(art.PutItemArtwork(&model.ItemArtwork{ItemKind: model.KindArtistArtwork.Prefix(), + ItemID: "ar-1", ImageType: model.ImageTypePrimary})).To(Succeed()) + + shown := storedSource(formatExplain(explainReport{kind: model.KindArtistArtwork, id: "ar-1", + stored: &model.ItemArtwork{AttemptedAt: time.Now()}})) + + q := ds.ArtworkQueue(ctx) + Expect(validateSources(q, repositorySources([]string{shown}))).To(Succeed(), + "explain's spelling of a source must be pasteable into --source") + Expect(validateSources(q, repositorySources([]string{"(" + shown + ")"}))).ToNot(Succeed(), + "a parenthesised name would be rejected, so explain must not print one") + }) +}) + var _ = Describe("repositorySources", func() { It("maps the user-facing absent name onto the stored empty source", func() { Expect(repositorySources([]string{"absent", "folder"})).To(Equal([]string{"", "folder"}))