summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-29 10:42:44 +0300
committerPaul Buetow <paul@buetow.org>2026-05-29 10:42:44 +0300
commit4513ccec70871532b5b06aed3f9ed720abf613ed (patch)
tree25affcce796b10407a7631b389ef291081195e8c /internal
parent78a1bada950fbdbbc9a3de1cf7bd9f87e7768d55 (diff)
refactor(showcase): extract summary and asset helpers (kq)
Diffstat (limited to 'internal')
-rw-r--r--internal/showcase/showcase.go79
-rw-r--r--internal/showcase/showcase_test.go112
2 files changed, 167 insertions, 24 deletions
diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go
index 936c9f4..e32d144 100644
--- a/internal/showcase/showcase.go
+++ b/internal/showcase/showcase.go
@@ -445,6 +445,54 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool
// Continue anyway with partial metadata
}
+ summary := g.resolveSummary(
+ repoName,
+ repoPath,
+ selectedTool,
+ readmeFile,
+ readmeContent,
+ readmeFound,
+ cachedSummary,
+ haveCachedSummary,
+ )
+
+ // Build URLs
+ codebergURL, githubURL, cgitURL := g.buildProjectLinks(repoName)
+
+ images, codeSnippet, codeLanguage, err := g.collectAssets(repoName, repoPath, statsRepoPath, metadata)
+ if err != nil {
+ return nil, err
+ }
+
+ projectSummary := &ProjectSummary{
+ Name: repoName,
+ Summary: summary,
+ CodebergURL: codebergURL,
+ GitHubURL: githubURL,
+ CgitURL: cgitURL,
+ Metadata: metadata,
+ Images: images,
+ CodeSnippet: codeSnippet,
+ CodeLanguage: codeLanguage,
+ }
+
+ // Save to cache
+ if err := g.saveToCache(cacheFile, projectSummary); err != nil {
+ fmt.Printf("Warning: Failed to save to cache: %v\n", err)
+ } else {
+ fmt.Printf("Summary cached at: %s\n", cacheFile)
+ }
+
+ return projectSummary, nil
+}
+
+func (g *Generator) resolveSummary(
+ repoName, repoPath, selectedTool, readmeFile string,
+ readmeContent []byte,
+ readmeFound bool,
+ cachedSummary string,
+ haveCachedSummary bool,
+) string {
// Get the summary - either from cache or by running AI tool
var summary string
if haveCachedSummary {
@@ -459,21 +507,23 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool
summary = fallbackSummary(repoName, readmeContent, readmeFound)
}
}
+
summary = extractUsefulSummary(summary, 2)
if summary == "" {
summary = fallbackSummary(repoName, readmeContent, readmeFound)
}
- summary = sanitizeSummaryForGemtext(summary)
- // Build URLs
- codebergURL, githubURL, cgitURL := g.buildProjectLinks(repoName)
+ return sanitizeSummaryForGemtext(summary)
+}
+func (g *Generator) collectAssets(repoName, repoPath, statsRepoPath string, metadata *RepoMetadata) ([]string, string, string, error) {
// Always extract images from README (not cached)
fmt.Printf("Extracting images from README...\n")
showcaseDir, err := showcaseOutputDir()
if err != nil {
- return nil, err
+ return nil, "", "", err
}
+
images, err := extractImagesFromRepo(repoPath, repoName, showcaseDir)
if err != nil {
fmt.Printf("Warning: Failed to extract images: %v\n", err)
@@ -492,26 +542,7 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool
}
}
- projectSummary := &ProjectSummary{
- Name: repoName,
- Summary: summary,
- CodebergURL: codebergURL,
- GitHubURL: githubURL,
- CgitURL: cgitURL,
- Metadata: metadata,
- Images: images,
- CodeSnippet: codeSnippet,
- CodeLanguage: codeLanguage,
- }
-
- // Save to cache
- if err := g.saveToCache(cacheFile, projectSummary); err != nil {
- fmt.Printf("Warning: Failed to save to cache: %v\n", err)
- } else {
- fmt.Printf("Summary cached at: %s\n", cacheFile)
- }
-
- return projectSummary, nil
+ return images, codeSnippet, codeLanguage, nil
}
// showcaseOutputDir returns the canonical directory where showcase output files
diff --git a/internal/showcase/showcase_test.go b/internal/showcase/showcase_test.go
index 6341e41..dac32b5 100644
--- a/internal/showcase/showcase_test.go
+++ b/internal/showcase/showcase_test.go
@@ -254,6 +254,118 @@ func TestFallbackSummary_SkipsHeadingOnlyParagraphs(t *testing.T) {
}
}
+func TestResolveSummary_CachedSummaryFallsBackToReadmeWhenNoUsefulParagraph(t *testing.T) {
+ t.Parallel()
+
+ g := &Generator{}
+ readmeContent := []byte("useful README summary paragraph")
+
+ got := g.resolveSummary(
+ "repo",
+ t.TempDir(),
+ "opencode",
+ "README.md",
+ readmeContent,
+ true,
+ "* item one\n* item two",
+ true,
+ )
+
+ if got != "useful README summary paragraph" {
+ t.Fatalf("resolveSummary() = %q, want README fallback", got)
+ }
+}
+
+func TestResolveSummary_NoCacheAndNoReadmeUsesGenericFallback(t *testing.T) {
+ t.Parallel()
+
+ g := &Generator{}
+
+ got := g.resolveSummary(
+ "repo",
+ t.TempDir(),
+ "opencode",
+ "",
+ nil,
+ false,
+ "",
+ false,
+ )
+
+ if got != "repo: source code repository." {
+ t.Fatalf("resolveSummary() = %q, want generic fallback", got)
+ }
+}
+
+func TestCollectAssets_ReturnsImagesAndSkipsSnippetWithoutLanguages(t *testing.T) {
+ homeDir := t.TempDir()
+ t.Setenv("HOME", homeDir)
+
+ repoName := "demo"
+ repoPath := filepath.Join(t.TempDir(), repoName)
+ if err := os.MkdirAll(repoPath, 0755); err != nil {
+ t.Fatalf("mkdir repo: %v", err)
+ }
+
+ if err := os.WriteFile(filepath.Join(repoPath, "README.md"), []byte("![screenshot](shot.png)"), 0644); err != nil {
+ t.Fatalf("write README.md: %v", err)
+ }
+ if err := os.WriteFile(filepath.Join(repoPath, "shot.png"), []byte("png"), 0644); err != nil {
+ t.Fatalf("write shot.png: %v", err)
+ }
+
+ g := &Generator{}
+ images, snippet, language, err := g.collectAssets(repoName, repoPath, repoPath, nil)
+ if err != nil {
+ t.Fatalf("collectAssets() error = %v", err)
+ }
+
+ if len(images) != 1 || images[0] != filepath.Join("showcase", repoName, "image-1.png") {
+ t.Fatalf("collectAssets() images = %#v", images)
+ }
+ if snippet != "" || language != "" {
+ t.Fatalf("collectAssets() snippet/language = %q/%q, want empty", snippet, language)
+ }
+
+ copiedPath := filepath.Join(homeDir, "git", "foo.zone-content", "gemtext", "about", images[0])
+ if _, err := os.Stat(copiedPath); err != nil {
+ t.Fatalf("expected copied image at %s: %v", copiedPath, err)
+ }
+}
+
+func TestCollectAssets_ContinuesWhenSnippetExtractionFails(t *testing.T) {
+ homeDir := t.TempDir()
+ t.Setenv("HOME", homeDir)
+
+ repoName := "demo"
+ repoPath := filepath.Join(t.TempDir(), repoName)
+ if err := os.MkdirAll(repoPath, 0755); err != nil {
+ t.Fatalf("mkdir repo: %v", err)
+ }
+
+ if err := os.WriteFile(filepath.Join(repoPath, "README.md"), []byte("![missing](missing.png)"), 0644); err != nil {
+ t.Fatalf("write README.md: %v", err)
+ }
+
+ g := &Generator{}
+ metadata := &RepoMetadata{
+ Languages: []LanguageStats{
+ {Name: "Go", Lines: 10, Percentage: 100},
+ },
+ }
+
+ images, snippet, language, err := g.collectAssets(repoName, repoPath, repoPath, metadata)
+ if err != nil {
+ t.Fatalf("collectAssets() error = %v", err)
+ }
+ if len(images) != 0 {
+ t.Fatalf("collectAssets() images = %#v, want no images", images)
+ }
+ if snippet != "" || language != "" {
+ t.Fatalf("collectAssets() snippet/language = %q/%q, want empty after extraction error", snippet, language)
+ }
+}
+
func TestSelectSummaryTool_DefaultPrefersOpencode(t *testing.T) {
t.Parallel()