From 09853197e5793e5e2fa4a3fda541c23c353aba8e Mon Sep 17 00:00:00 2001 From: butakero Date: Mon, 17 Feb 2025 11:43:43 -0300 Subject: [PATCH 1/2] fix: Improve error handling and internationalization --- cmd/main.go | 2 +- internal/i18n/locales/active.en.toml | 19 ++++++- internal/i18n/locales/active.es.toml | 19 ++++++- .../ai/gemini/gemini_pr_summarizer_service.go | 11 +++- .../ai/gemini/gemini_service.go | 30 ++++------ .../factory/pr_service_factory.go | 2 +- internal/services/commit_service.go | 55 ++++++++++++------- internal/services/commit_service_test.go | 50 ++++++++++++----- internal/services/pr_service.go | 20 +++++-- internal/services/pr_service_test.go | 35 +++++++----- 10 files changed, 164 insertions(+), 79 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 7f15e97..da449b4 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -66,7 +66,7 @@ func initializeApp() (*cli.Command, error) { ticketService := jira.NewJiraService(cfgApp, &http.Client{}) - commitService := services.NewCommitService(gitService, aiProvider, ticketService, cfgApp) + commitService := services.NewCommitService(gitService, aiProvider, ticketService, cfgApp, translations) commitHandler := handler.NewSuggestionHandler(gitService, translations) diff --git a/internal/i18n/locales/active.en.toml b/internal/i18n/locales/active.en.toml index 39de2be..9b61a39 100644 --- a/internal/i18n/locales/active.en.toml +++ b/internal/i18n/locales/active.en.toml @@ -167,6 +167,9 @@ missing_criteria_none = "✅ Missing Criteria: None" pr_title_section = "PR Title" pr_labels_section = "Suggested Tags" pr_changes_section = "Key Changes" +error_gemini_client = "Error creating Gemini client: {{.Error}}" +response_empty = "Empty AI response" +title_not_found = "The title was not found in the answer" [suggestion_header] other = "=========[ Suggestion {{.Number}} ]=========" @@ -230,4 +233,18 @@ config_set_vcs_repo_usage = "Name of the repository" config_vcs_updated = "VCS provider '{{.Provider}}' configuration updated successfully" config_set_active_vcs_usage = "Set the active VCS provider" config_set_active_vcs_provider_usage = "Name of the VCS provider to set as active" -config_active_vcs_updated = "Active VCS provider set to '{{.Provider}}'" \ No newline at end of file +config_active_vcs_updated = "Active VCS provider set to '{{.Provider}}'" + +[commit_service] +undetected_changes = "No changes detected" +error_getting_diff = "Error getting changes: {{.Error}}" +no_differences_detected = "No differences were detected in the files" +error_get_id_ticket = "Error getting ticket ID: {{.Error}}" +error_get_ticket_info = "Error obtaining ticket information: {{.Error}}" +ticket_id_not_found_branch = "No ticket ID found in the branch name" +error_get_name_from_branch = "Error getting branch name: {{.Error}}" + +[pr_service] +error_get_pr = "Error getting the PR: {{.Error}}" +error_create_summary_pr = "Error creating PR summary: {{.Error}}" +error_update_pr = "Error updating PR: {{.Error}}" \ No newline at end of file diff --git a/internal/i18n/locales/active.es.toml b/internal/i18n/locales/active.es.toml index e430f3d..ccb9499 100644 --- a/internal/i18n/locales/active.es.toml +++ b/internal/i18n/locales/active.es.toml @@ -175,6 +175,9 @@ technical_analysis_section = "💭 Analisis Tecnico:" pr_title_section = "Titulo del PR" pr_labels_section = "Etiquetas sugeridas" pr_changes_section = "Cambios Clave" +error_gemini_client = "Error al crear el cliente de Gemini: {{.Error}}" +response_empty = "Respuesta de la IA vacia" +title_not_found = "No se encontro el titulo en la respuesta" [suggestion_header] other = "=========[ Sugerencias {{.Number}} ]=========" @@ -237,4 +240,18 @@ config_set_vcs_repo_usage = "Nombre del repositorio" config_vcs_updated = "Configuración del proveedor VCS '{{.Provider}}' actualizada correctamente" config_set_active_vcs_usage = "Establecer el proveedor VCS activo" config_set_active_vcs_provider_usage = "Nombre del proveedor VCS a establecer como activo" -config_active_vcs_updated = "Proveedor VCS activo establecido a '{{.Provider}}'" \ No newline at end of file +config_active_vcs_updated = "Proveedor VCS activo establecido a '{{.Provider}}'" + +[commit_service] +undetected_changes = "No hay cambios detectados" +error_getting_diff = "Error al obtener los cambios: {{.Error}}" +no_differences_detected = "No se detectaron diferencias en los archivos" +error_get_id_ticket = "Error al obtener el ID del ticket: {{.Error}}" +error_get_ticket_info = "Error al obtener informacion del ticket: {{.Error}}" +ticket_id_not_found_branch = "No se encontro un ID de ticket en el nombre de la branch" +error_get_name_from_branch = "Error al obtener el nombre de la branch: {{.Error}}" + +[pr_service] +error_get_pr = "Error al obtener el PR: {{.Error}}" +error_create_summary_pr = "Error al crear el resumen del PR: {{.Error}}" +error_update_pr = "Error al actualizar el PR: {{.Error}}" \ No newline at end of file diff --git a/internal/infrastructure/ai/gemini/gemini_pr_summarizer_service.go b/internal/infrastructure/ai/gemini/gemini_pr_summarizer_service.go index 31fb7b9..d6633d4 100644 --- a/internal/infrastructure/ai/gemini/gemini_pr_summarizer_service.go +++ b/internal/infrastructure/ai/gemini/gemini_pr_summarizer_service.go @@ -28,7 +28,10 @@ func NewGeminiPRSummarizer(ctx context.Context, cfg *config.Config, trans *i18n. client, err := genai.NewClient(ctx, option.WithAPIKey(cfg.GeminiAPIKey)) if err != nil { - return nil, fmt.Errorf("failed to create Gemini client: %w", err) + msg := trans.GetMessage("error_gemini_client", 0, map[string]interface{}{ + "Error": err, + }) + return nil, fmt.Errorf("%s", msg) } modelName := string(cfg.AIConfig.Models[config.AIGemini]) @@ -57,7 +60,8 @@ func (gps *GeminiPRSummarizer) GeneratePRSummary(ctx context.Context, prompt str rawSummary := formatResponse(resp) if rawSummary == "" { - return models.PRSummary{}, fmt.Errorf("respuesta vacía de la IA") + msg := gps.trans.GetMessage("gemini_service.response_empty", 0, nil) + return models.PRSummary{}, fmt.Errorf("%s", msg) } return gps.parseSummary(rawSummary) @@ -113,7 +117,8 @@ func (gps *GeminiPRSummarizer) parseSummary(raw string) (models.PRSummary, error summary.Body = strings.Join(bodyParts, "\n\n") if summary.Title == "" { - return summary, fmt.Errorf("no se encontró el título en la respuesta") + msg := gps.trans.GetMessage("title_not_found", 0, nil) + return summary, fmt.Errorf("%s", msg) } if utf8.RuneCountInString(summary.Title) > 80 { diff --git a/internal/infrastructure/ai/gemini/gemini_service.go b/internal/infrastructure/ai/gemini/gemini_service.go index bba15b1..71bc8df 100644 --- a/internal/infrastructure/ai/gemini/gemini_service.go +++ b/internal/infrastructure/ai/gemini/gemini_service.go @@ -27,7 +27,10 @@ func NewGeminiService(ctx context.Context, cfg *config.Config, trans *i18n.Trans } client, err := genai.NewClient(ctx, option.WithAPIKey(cfg.GeminiAPIKey)) if err != nil { - return nil, fmt.Errorf("failed to create Gemini client: %w", err) + msg := trans.GetMessage("error_gemini_client", 0, map[string]interface{}{ + "Error": err, + }) + return nil, fmt.Errorf("%s", msg) } modelName := string(cfg.AIConfig.Models[config.AIGemini]) @@ -73,7 +76,6 @@ func (s *GeminiService) GenerateSuggestions(ctx context.Context, info models.Com func (s *GeminiService) generatePrompt(locale string, info models.CommitInfo, count int) string { promptTemplate := ai.GetCommitPromptTemplate(locale, info.TicketInfo != nil && info.TicketInfo.TicketTitle != "") - // Preparar la información del ticket si existe ticketInfo := "" if info.TicketInfo != nil && info.TicketInfo.TicketTitle != "" { ticketInfo = fmt.Sprintf("\nTicket Title: %s\nTicket Description: %s\nAcceptance Criteria: %s", @@ -82,13 +84,12 @@ func (s *GeminiService) generatePrompt(locale string, info models.CommitInfo, co strings.Join(info.TicketInfo.Criteria, ", ")) } - // El orden de los argumentos debe coincidir con los placeholders en el template return fmt.Sprintf(promptTemplate, - count, // Primer %d - count, // Segundo %d - formatChanges(info.Files), // %s para archivos modificados - info.Diff, // %s para el diff - ticketInfo, // %s para la información del ticket + count, + count, + formatChanges(info.Files), + info.Diff, + ticketInfo, ) } @@ -139,7 +140,7 @@ func (s *GeminiService) parseSuggestions(resp *genai.GenerateContentResponse) [] delimiter := s.getSuggestionDelimiter() re := regexp.MustCompile(delimiter) - parts := re.Split(responseText, -1) // Dividir usando regex + parts := re.Split(responseText, -1) suggestions := make([]models.CommitSuggestion, 0) for _, part := range parts { @@ -168,7 +169,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio RequirementsAnalysis: models.RequirementsAnalysis{}, } - // Extraer el título del commit for _, line := range lines { if strings.HasPrefix(line, "Commit:") { suggestion.CommitTitle = strings.TrimSpace(strings.TrimPrefix(line, "Commit:")) @@ -176,7 +176,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio } } - // Extraer los archivos modificados var collectingFiles bool for _, line := range lines { trimmedLine := strings.TrimSpace(line) @@ -196,7 +195,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio } } - // Extraer la explicación var explanation strings.Builder for _, line := range lines { if strings.HasPrefix(line, s.trans.GetMessage("gemini_service.explanation_prefix", 0, nil)) { @@ -206,7 +204,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio } suggestion.Explanation = strings.TrimSpace(explanation.String()) - // Extraer el análisis de código for i, line := range lines { if strings.HasPrefix(line, s.trans.GetMessage("gemini_service.code_analysis_prefix", 0, nil)) { if i+1 < len(lines) && strings.HasPrefix(lines[i+1], s.trans.GetMessage("gemini_service.changes_overview_prefix", 0, nil)) { @@ -222,7 +219,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio } } - // Extraer el análisis de requisitos var ( collectingMissingCriteria bool collectingImprovements bool @@ -231,7 +227,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio for _, line := range lines { trimmedLine := strings.TrimSpace(line) - // Procesar estado de criterios if strings.HasPrefix(trimmedLine, "⚠️") { switch { case strings.Contains(trimmedLine, s.trans.GetMessage("gemini_service.criteria_fully_met_prefix", 0, nil)): @@ -244,21 +239,18 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio continue } - // Procesar criterios faltantes if strings.HasPrefix(trimmedLine, "❌") { collectingMissingCriteria = true collectingImprovements = false continue } - // Procesar sugerencias de mejora if strings.HasPrefix(trimmedLine, "💡") { collectingMissingCriteria = false collectingImprovements = true continue } - // Recolectar criterios faltantes if collectingMissingCriteria && strings.HasPrefix(trimmedLine, "-") { criteria := strings.TrimSpace(strings.TrimPrefix(trimmedLine, "-")) suggestion.RequirementsAnalysis.MissingCriteria = append( @@ -267,7 +259,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio ) } - // Recolectar sugerencias de mejora if collectingImprovements && strings.HasPrefix(trimmedLine, "-") { improvement := strings.TrimSpace(strings.TrimPrefix(trimmedLine, "-")) suggestion.RequirementsAnalysis.ImprovementSuggestions = append( @@ -276,7 +267,6 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio ) } - // Detener la recolección si encontramos una línea vacía o un nuevo encabezado if trimmedLine == "" || strings.HasPrefix(trimmedLine, "📊") || strings.HasPrefix(trimmedLine, "📝") { collectingMissingCriteria = false diff --git a/internal/infrastructure/factory/pr_service_factory.go b/internal/infrastructure/factory/pr_service_factory.go index 687aed8..043c2f6 100644 --- a/internal/infrastructure/factory/pr_service_factory.go +++ b/internal/infrastructure/factory/pr_service_factory.go @@ -43,5 +43,5 @@ func (f *PRServiceFactory) CreatePRService() (ports.PRService, error) { return nil, fmt.Errorf("proveedor de VCS no compatible: %s", vcsConfig.Provider) } - return services.NewPRService(vcsClient, f.aiService), nil + return services.NewPRService(vcsClient, f.aiService, f.trans), nil } diff --git a/internal/services/commit_service.go b/internal/services/commit_service.go index 39e6ae4..3c9553b 100644 --- a/internal/services/commit_service.go +++ b/internal/services/commit_service.go @@ -2,50 +2,56 @@ package services import ( "context" - "errors" "fmt" "github.com/Tomas-vilte/MateCommit/internal/config" "github.com/Tomas-vilte/MateCommit/internal/domain/models" "github.com/Tomas-vilte/MateCommit/internal/domain/ports" + "github.com/Tomas-vilte/MateCommit/internal/i18n" "regexp" ) type CommitService struct { - git ports.GitService - ai ports.AIProvider - jiraService ports.TickerManager - config *config.Config + git ports.GitService + ai ports.AIProvider + ticketManager ports.TickerManager + config *config.Config + trans *i18n.Translations } -func NewCommitService(git ports.GitService, ai ports.AIProvider, jiraService ports.TickerManager, cfg *config.Config) *CommitService { +func NewCommitService(git ports.GitService, ai ports.AIProvider, ticketManager ports.TickerManager, cfg *config.Config, trans *i18n.Translations) *CommitService { return &CommitService{ - git: git, - ai: ai, - jiraService: jiraService, - config: cfg, + git: git, + ai: ai, + ticketManager: ticketManager, + config: cfg, + trans: trans, } } func (s *CommitService) GenerateSuggestions(ctx context.Context, count int) ([]models.CommitSuggestion, error) { var commitInfo models.CommitInfo - // Obtener los cambios en el código changes, err := s.git.GetChangedFiles() if err != nil { return nil, err } if len(changes) == 0 { - return nil, fmt.Errorf("no hay cambios detectados") + msg := s.trans.GetMessage("commit_service.undetected_changes", 0, nil) + return nil, fmt.Errorf("%s", msg) } diff, err := s.git.GetDiff() if err != nil { - return nil, fmt.Errorf("error al obtener el diff: %v", err) + msg := s.trans.GetMessage("commit_service.error_getting_diff", 0, map[string]interface{}{ + "Error": err, + }) + return nil, fmt.Errorf("%s", msg) } if diff == "" { - return nil, errors.New("no se detectaron diferencias en los archivos") + msg := s.trans.GetMessage("commit_service.no_differences_detected", 0, nil) + return nil, fmt.Errorf("%s", msg) } files := make([]string, 0) @@ -61,31 +67,40 @@ func (s *CommitService) GenerateSuggestions(ctx context.Context, count int) ([]m if s.config.UseTicket { ticketID, err := s.getTicketIDFromBranch() if err != nil { - return nil, fmt.Errorf("error al obtener el ID del ticket: %v", err) + msg := s.trans.GetMessage("commit_service.error_get_id_ticket", 0, map[string]interface{}{ + "Error": err, + }) + return nil, fmt.Errorf("%s", msg) } - ticketInfo, err := s.jiraService.GetTicketInfo(ticketID) + ticketInfo, err := s.ticketManager.GetTicketInfo(ticketID) if err != nil { - return nil, fmt.Errorf("error al obtener la información del ticket: %v", err) + msg := s.trans.GetMessage("commit_service.error_get_ticket_info", 0, map[string]interface{}{ + "Error": err, + }) + return nil, fmt.Errorf("%s", msg) } commitInfo.TicketInfo = ticketInfo } - // Generar sugerencias de commit usando la IA return s.ai.GenerateSuggestions(ctx, commitInfo, count) } func (s *CommitService) getTicketIDFromBranch() (string, error) { branchName, err := s.git.GetCurrentBranch() if err != nil { - return "", fmt.Errorf("error al obtener el nombre de la branch: %v", err) + msg := s.trans.GetMessage("commit_service.error_get_name_from_branch", 0, map[string]interface{}{ + "Error": err, + }) + return "", fmt.Errorf("%s", msg) } re := regexp.MustCompile(`([A-Za-z]+-\d+)`) match := re.FindString(branchName) if match == "" { - return "", fmt.Errorf("no se encontró un ID de ticket en el nombre de la branch") + msg := s.trans.GetMessage("commit_service.ticket_id_not_found_branch", 0, nil) + return "", fmt.Errorf("%s", msg) } return match, nil diff --git a/internal/services/commit_service_test.go b/internal/services/commit_service_test.go index f84b258..a31a982 100644 --- a/internal/services/commit_service_test.go +++ b/internal/services/commit_service_test.go @@ -5,8 +5,10 @@ import ( "errors" "github.com/Tomas-vilte/MateCommit/internal/config" "github.com/Tomas-vilte/MateCommit/internal/domain/models" + "github.com/Tomas-vilte/MateCommit/internal/i18n" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "testing" ) @@ -75,6 +77,8 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("feature/PROJ-1234-user-authentication", nil) @@ -110,7 +114,7 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -130,10 +134,12 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetChangedFiles").Return([]models.GitChange{}, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -141,7 +147,7 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { // assert assert.Error(t, err) assert.Nil(t, suggestions) - assert.EqualError(t, err, "no hay cambios detectados") + assert.EqualError(t, err, "No hay cambios detectados") mockGit.AssertExpectations(t) }) @@ -152,6 +158,8 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) changes := []models.GitChange{ { @@ -162,7 +170,7 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { mockGit.On("GetChangedFiles").Return(changes, nil) mockGit.On("GetDiff").Return("", errors.New("git error")) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -170,7 +178,7 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { // assert assert.Error(t, err) assert.Nil(t, suggestions) - assert.EqualError(t, err, "error al obtener el diff: git error") + assert.EqualError(t, err, "Error al obtener los cambios: git error") mockGit.AssertExpectations(t) }) @@ -181,12 +189,14 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetChangedFiles").Return([]models.GitChange{{Path: "file1.go", Status: "M"}}, nil) mockGit.On("GetDiff").Return("some diff", nil) mockGit.On("GetCurrentBranch").Return("main", nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -194,7 +204,7 @@ func TestCommitService_GenerateSuggestions(t *testing.T) { // assert assert.Error(t, err) assert.Nil(t, suggestions) - assert.EqualError(t, err, "error al obtener el ID del ticket: no se encontró un ID de ticket en el nombre de la branch") + assert.EqualError(t, err, "Error al obtener el ID del ticket: No se encontro un ID de ticket en el nombre de la branch") mockGit.AssertExpectations(t) }) @@ -233,6 +243,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("feature/PROJ-1234-user-authentication", nil) @@ -268,7 +280,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -288,6 +300,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("bugfix/PROJ-5678-fix-login", nil) @@ -323,7 +337,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -343,6 +357,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("hotfix/PROJ-9999-critical-bug", nil) @@ -378,7 +394,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -398,6 +414,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("release/PROJ-1000-final-release", nil) @@ -433,7 +451,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -453,6 +471,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("main", nil) @@ -463,7 +483,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockGit.On("GetChangedFiles").Return(changes, nil) mockGit.On("GetDiff").Return("some diff", nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) @@ -471,7 +491,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { // Assert assert.Error(t, err) assert.Nil(t, suggestions) - assert.EqualError(t, err, "error al obtener el ID del ticket: no se encontró un ID de ticket en el nombre de la branch") + assert.EqualError(t, err, "Error al obtener el ID del ticket: No se encontro un ID de ticket en el nombre de la branch") mockGit.AssertExpectations(t) }) @@ -482,6 +502,8 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { mockAI := new(MockAIProvider) mockJiraService := new(MockJiraService) cfgApp := &config.Config{UseTicket: true} + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) mockGit.On("GetCurrentBranch").Return("custom/PROJ-2000-custom-feature", nil) @@ -517,7 +539,7 @@ func TestCommitService_GenerateSuggestions_DifferentBranchNames(t *testing.T) { } mockAI.On("GenerateSuggestions", mock.Anything, expectedInfo, 3).Return(expectedResponse, nil) - service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp) + service := NewCommitService(mockGit, mockAI, mockJiraService, cfgApp, trans) // Act suggestions, err := service.GenerateSuggestions(context.Background(), 3) diff --git a/internal/services/pr_service.go b/internal/services/pr_service.go index 65070ff..efb755f 100644 --- a/internal/services/pr_service.go +++ b/internal/services/pr_service.go @@ -5,36 +5,48 @@ import ( "fmt" "github.com/Tomas-vilte/MateCommit/internal/domain/models" "github.com/Tomas-vilte/MateCommit/internal/domain/ports" + "github.com/Tomas-vilte/MateCommit/internal/i18n" ) type PRService struct { vcsClient ports.VCSClient aiService ports.PRSummarizer + trans *i18n.Translations } -func NewPRService(vcsClient ports.VCSClient, aiService ports.PRSummarizer) *PRService { +func NewPRService(vcsClient ports.VCSClient, aiService ports.PRSummarizer, trans *i18n.Translations) *PRService { return &PRService{ vcsClient: vcsClient, aiService: aiService, + trans: trans, } } func (s *PRService) SummarizePR(ctx context.Context, prNumber int) (models.PRSummary, error) { prData, err := s.vcsClient.GetPR(ctx, prNumber) if err != nil { - return models.PRSummary{}, fmt.Errorf("hubo un error al obtener el pr: %w", err) + msg := s.trans.GetMessage("pr_service.error_get_pr", 0, map[string]interface{}{ + "Error": err, + }) + return models.PRSummary{}, fmt.Errorf("%s", msg) } prompt := s.buildPRPrompt(prData) summary, err := s.aiService.GeneratePRSummary(ctx, prompt) if err != nil { - return models.PRSummary{}, fmt.Errorf("hubo un error al crear el resumen del pull requests: %w", err) + msg := s.trans.GetMessage("pr_service.error_create_summary_pr", 0, map[string]interface{}{ + "Error": err, + }) + return models.PRSummary{}, fmt.Errorf("%s", msg) } err = s.vcsClient.UpdatePR(ctx, prNumber, summary) if err != nil { - return models.PRSummary{}, fmt.Errorf("hubo un error al actualizar el pull requests: %w", err) + msg := s.trans.GetMessage("pr_service.error_update_pr", 0, map[string]interface{}{ + "Error": err, + }) + return models.PRSummary{}, fmt.Errorf("%s", msg) } return summary, nil diff --git a/internal/services/pr_service_test.go b/internal/services/pr_service_test.go index e7714b9..7e09b7a 100644 --- a/internal/services/pr_service_test.go +++ b/internal/services/pr_service_test.go @@ -60,6 +60,8 @@ func TestPRService_SummarizePR_Success(t *testing.T) { mockVCS := new(MockVCSClient) mockAI := new(MockPRSummarizer) + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) prData := models.PRData{ ID: 123, @@ -81,7 +83,7 @@ func TestPRService_SummarizePR_Success(t *testing.T) { mockAI.On("GeneratePRSummary", ctx, mock.AnythingOfType("string")).Return(expectedSummary, nil) mockVCS.On("UpdatePR", ctx, prNumber, expectedSummary).Return(nil) - service := NewPRService(mockVCS, mockAI) + service := NewPRService(mockVCS, mockAI, trans) // Act result, err := service.SummarizePR(ctx, prNumber) @@ -99,19 +101,21 @@ func TestPRService_SummarizePR_GetPRError(t *testing.T) { mockVCS := new(MockVCSClient) mockAI := new(MockPRSummarizer) + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) expectedError := errors.New("API error") mockVCS.On("GetPR", ctx, prNumber).Return(models.PRData{}, expectedError) - service := NewPRService(mockVCS, mockAI) + service := NewPRService(mockVCS, mockAI, trans) // act - _, err := service.SummarizePR(ctx, prNumber) + _, err = service.SummarizePR(ctx, prNumber) // assert - assert.ErrorContains(t, err, "hubo un error al obtener el pr") - assert.ErrorIs(t, err, expectedError) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Error al obtener el PR") mockVCS.AssertExpectations(t) mockAI.AssertNotCalled(t, "GeneratePRSummary") } @@ -122,6 +126,8 @@ func TestPRService_SummarizePR_GenerateError(t *testing.T) { mockVCS := new(MockVCSClient) mockAI := new(MockPRSummarizer) + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) prData := models.PRData{ ID: 123, @@ -135,14 +141,14 @@ func TestPRService_SummarizePR_GenerateError(t *testing.T) { mockVCS.On("GetPR", ctx, prNumber).Return(prData, nil) mockAI.On("GeneratePRSummary", ctx, mock.Anything).Return(models.PRSummary{}, expectedError) - service := NewPRService(mockVCS, mockAI) + service := NewPRService(mockVCS, mockAI, trans) // Act - _, err := service.SummarizePR(ctx, prNumber) + _, err = service.SummarizePR(ctx, prNumber) // Assert - assert.ErrorContains(t, err, "hubo un error al crear el resumen del pull requests") - assert.ErrorIs(t, err, expectedError) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Error al crear el resumen del PR") mockVCS.AssertExpectations(t) mockAI.AssertExpectations(t) mockVCS.AssertNotCalled(t, "UpdatePR") @@ -154,6 +160,8 @@ func TestPRService_SummarizePR_UpdateError(t *testing.T) { mockVCS := new(MockVCSClient) mockAI := new(MockPRSummarizer) + trans, err := i18n.NewTranslations("es", "../i18n/locales") + require.NoError(t, err) prData := models.PRData{ ID: 123, @@ -173,12 +181,11 @@ func TestPRService_SummarizePR_UpdateError(t *testing.T) { mockAI.On("GeneratePRSummary", ctx, mock.Anything).Return(summary, nil) mockVCS.On("UpdatePR", ctx, prNumber, summary).Return(expectedError) - service := NewPRService(mockVCS, mockAI) + service := NewPRService(mockVCS, mockAI, trans) - _, err := service.SummarizePR(ctx, prNumber) + _, err = service.SummarizePR(ctx, prNumber) - assert.ErrorContains(t, err, "hubo un error al actualizar el pull requests") - assert.ErrorIs(t, err, expectedError) + assert.ErrorContains(t, err, "Error al actualizar el PR: update failed") mockVCS.AssertExpectations(t) mockAI.AssertExpectations(t) } @@ -267,7 +274,7 @@ func setupServices(t *testing.T, testConfig TestConfig) (*PRService, error) { return nil, err } - prService := NewPRService(githubClient, geminiSummarizer) + prService := NewPRService(githubClient, geminiSummarizer, trans) return prService, nil } From d745c0deb1b64a785f6636f83aefd1ac335e4ab6 Mon Sep 17 00:00:00 2001 From: butakero Date: Mon, 17 Feb 2025 11:50:58 -0300 Subject: [PATCH 2/2] chore: Simplify release process by removing unnecessary archives --- .goreleaser.yml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 749c742..9e0dcca 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,20 +21,6 @@ builds: - -X main.commit={{.Commit}} - -X main.date={{.Date}} -archives: - - id: default - format: tar.gz - files: - - locales/** - name_template: >- - {{ .ProjectName }}_{{ .Version }}_ - {{- title .Os }}_ - {{- if eq .Arch "amd64" }}x86_64 - {{- else }}{{ .Arch }}{{ end }} - format_overrides: - - goos: windows - format: zip - checksum: name_template: 'checksums.txt' @@ -47,4 +33,4 @@ changelog: - Merge pull request - Merge branch -version: 2 \ No newline at end of file +version: 2