From 1bf3a6227f76644ffc46070087bab973a68829d2 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 12 Jul 2025 14:26:33 +0300 Subject: feat: improve AI release notes generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Display Claude CLI command being executed with prompt length - Cache AI-generated release notes to avoid regenerating for same tag - Use cached notes when creating/updating releases on different platforms - Show when falling back to different Claude models 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- internal/cli/release.go | 91 ++++++++++++++++++++++++++++++++------------- internal/release/release.go | 6 +++ 2 files changed, 71 insertions(+), 26 deletions(-) (limited to 'internal') diff --git a/internal/cli/release.go b/internal/cli/release.go index 97c97cd..c882677 100644 --- a/internal/cli/release.go +++ b/internal/cli/release.go @@ -59,6 +59,9 @@ func HandleCheckReleasesForRepo(cfg *config.Config, flags *Flags, repoName strin func HandleCheckReleasesForRepos(cfg *config.Config, flags *Flags, repositories []string) int { releaseManager := release.NewManager(flags.WorkDir) + // Cache for AI release notes to avoid regenerating for the same repo/tag + aiReleaseNotesCache := make(map[string]string) // key: "repoName:tag" + // Set tokens from config with fallback to environment variables and files githubOrg := cfg.FindGitHubOrg() if githubOrg != nil { @@ -189,15 +192,23 @@ func HandleCheckReleasesForRepos(cfg *config.Config, flags *Flags, repositories // Generate release notes var releaseNotes string if flags.AIReleaseNotes { - fmt.Printf(" Generating AI release notes for %s...\n", tag) - aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) - if err != nil { - fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) - fmt.Printf(" Falling back to standard release notes\n") - releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) + // Check cache first + cacheKey := fmt.Sprintf("%s:%s", repoName, tag) + if cachedNotes, exists := aiReleaseNotesCache[cacheKey]; exists { + fmt.Printf(" Using cached AI release notes for %s\n", tag) + releaseNotes = cachedNotes } else { - releaseNotes = aiNotes - fmt.Printf(" AI release notes generated successfully\n") + fmt.Printf(" Generating AI release notes for %s...\n", tag) + aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) + if err != nil { + fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) + fmt.Printf(" Falling back to standard release notes\n") + releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) + } else { + releaseNotes = aiNotes + aiReleaseNotesCache[cacheKey] = aiNotes // Cache the result + fmt.Printf(" AI release notes generated successfully\n") + } } } else { releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) @@ -242,15 +253,23 @@ func HandleCheckReleasesForRepos(cfg *config.Config, flags *Flags, repositories // Generate release notes var releaseNotes string if flags.AIReleaseNotes { - fmt.Printf(" Generating AI release notes for %s...\n", tag) - aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) - if err != nil { - fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) - fmt.Printf(" Falling back to standard release notes\n") - releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) + // Check cache first + cacheKey := fmt.Sprintf("%s:%s", repoName, tag) + if cachedNotes, exists := aiReleaseNotesCache[cacheKey]; exists { + fmt.Printf(" Using cached AI release notes for %s\n", tag) + releaseNotes = cachedNotes } else { - releaseNotes = aiNotes - fmt.Printf(" AI release notes generated successfully\n") + fmt.Printf(" Generating AI release notes for %s...\n", tag) + aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) + if err != nil { + fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) + fmt.Printf(" Falling back to standard release notes\n") + releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) + } else { + releaseNotes = aiNotes + aiReleaseNotesCache[cacheKey] = aiNotes // Cache the result + fmt.Printf(" AI release notes generated successfully\n") + } } } else { releaseNotes = releaseManager.GenerateReleaseNotes(repoPath, tag, localTags) @@ -305,11 +324,21 @@ func HandleCheckReleasesForRepos(cfg *config.Config, flags *Flags, repositories // Generate AI release notes if flags.AIReleaseNotes { - fmt.Printf(" Generating AI release notes for existing release %s...\n", tag) - aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) - if err != nil { - fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) - continue + // Check cache first + cacheKey := fmt.Sprintf("%s:%s", repoName, tag) + var aiNotes string + if cachedNotes, exists := aiReleaseNotesCache[cacheKey]; exists { + fmt.Printf(" Using cached AI release notes for existing release %s\n", tag) + aiNotes = cachedNotes + } else { + fmt.Printf(" Generating AI release notes for existing release %s...\n", tag) + var err error + aiNotes, err = releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) + if err != nil { + fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) + continue + } + aiReleaseNotesCache[cacheKey] = aiNotes // Cache the result } // Print release notes to stdout @@ -360,11 +389,21 @@ func HandleCheckReleasesForRepos(cfg *config.Config, flags *Flags, repositories // Generate AI release notes if flags.AIReleaseNotes { - fmt.Printf(" Generating AI release notes for existing release %s...\n", tag) - aiNotes, err := releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) - if err != nil { - fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) - continue + // Check cache first + cacheKey := fmt.Sprintf("%s:%s", repoName, tag) + var aiNotes string + if cachedNotes, exists := aiReleaseNotesCache[cacheKey]; exists { + fmt.Printf(" Using cached AI release notes for existing release %s\n", tag) + aiNotes = cachedNotes + } else { + fmt.Printf(" Generating AI release notes for existing release %s...\n", tag) + var err error + aiNotes, err = releaseManager.GenerateAIReleaseNotes(repoPath, repoName, tag, localTags, commits) + if err != nil { + fmt.Printf(" Warning: Failed to generate AI release notes: %v\n", err) + continue + } + aiReleaseNotesCache[cacheKey] = aiNotes // Cache the result } // Print release notes to stdout diff --git a/internal/release/release.go b/internal/release/release.go index 67350cf..ec4eaae 100644 --- a/internal/release/release.go +++ b/internal/release/release.go @@ -329,14 +329,20 @@ func (m *Manager) GenerateAIReleaseNotes(repoPath, repoName, tag string, allTags prompt.WriteString("\nDo not include the version number in the title as it will be added automatically.") // Run Claude CLI + fmt.Println(" Running Claude CLI command:") + fmt.Printf(" claude --model sonnet-3.5 \n") + fmt.Printf(" Prompt length: %d characters\n", len(prompt.String())) + cmd := exec.Command("claude", "--model", "sonnet-3.5", prompt.String()) output, err := cmd.Output() if err != nil { // Try with sonnet-4 model + fmt.Println(" Trying with sonnet-4 model...") cmd = exec.Command("claude", "--model", "sonnet-4", prompt.String()) output, err = cmd.Output() if err != nil { // Try with default model + fmt.Println(" Trying with default model...") cmd = exec.Command("claude", prompt.String()) output, err = cmd.Output() if err != nil { -- cgit v1.2.3