Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (

"github.com/Tomas-vilte/MateCommit/internal/cli/command/config"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/handler"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/pr"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/pull_requests"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/release"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/suggest"
"github.com/Tomas-vilte/MateCommit/internal/cli/command/suggests_commits"
"github.com/Tomas-vilte/MateCommit/internal/cli/registry"
cfg "github.com/Tomas-vilte/MateCommit/internal/config"
"github.com/Tomas-vilte/MateCommit/internal/i18n"
Expand Down Expand Up @@ -72,17 +72,17 @@ func initializeApp() (*cli.Command, error) {

ticketService := jira.NewJiraService(cfgApp, &http.Client{})

commitService := services.NewCommitService(gitService, aiProvider, ticketService, cfgApp, translations)
commitService := services.NewCommitService(gitService, aiProvider, ticketService, nil, cfgApp, translations)

commitHandler := handler.NewSuggestionHandler(gitService, translations)

registerCommand := registry.NewRegistry(cfgApp, translations)

prServiceFactory := factory.NewPrServiceFactory(cfgApp, translations, aiSummarizer, gitService)

prCommand := pr.NewSummarizeCommand(prServiceFactory)
prCommand := pull_requests.NewSummarizeCommand(prServiceFactory)

if err := registerCommand.Register("suggest", suggest.NewSuggestCommandFactory(commitService, commitHandler)); err != nil {
if err := registerCommand.Register("suggest", suggests_commits.NewSuggestCommandFactory(commitService, commitHandler)); err != nil {
log.Fatalf("Error al registrar el comando 'suggest': %v", err)
}

Expand Down
5 changes: 5 additions & 0 deletions internal/cli/command/handler/suggestions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ func (m *mockGitService) PushTag(ctx context.Context, version string) error {
return args.Error(0)
}

func (m *mockGitService) GetRecentCommitMessages(ctx context.Context, count int) (string, error) {
args := m.Called(ctx, count)
return args.String(0), args.Error(1)
}

func captureOutput(f func()) string {
old := os.Stdout
r, w, _ := os.Pipe()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pr
package pull_requests

import (
"context"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pr
package pull_requests

import (
"context"
Expand Down
5 changes: 5 additions & 0 deletions internal/cli/command/release/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,8 @@ func (m *MockGitService) PushTag(ctx context.Context, version string) error {
args := m.Called(ctx, version)
return args.Error(0)
}

func (m *MockGitService) GetRecentCommitMessages(ctx context.Context, count int) (string, error) {
args := m.Called(ctx, count)
return args.String(0), args.Error(1)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package suggest
package suggests_commits

import (
"context"
"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"
"github.com/urfave/cli/v3"
Expand Down Expand Up @@ -53,16 +54,22 @@ func (f *SuggestCommandFactory) createFlags(cfg *config.Config, t *i18n.Translat
Value: cfg.UseEmoji,
Usage: t.GetMessage("suggest_no_emoji_flag_usage", 0, nil),
},
&cli.IntFlag{
Name: "issue",
Aliases: []string{"i"},
Usage: t.GetMessage("suggest_issue_flag_usage", 0, nil),
Value: 0,
},
}
}

func (f *SuggestCommandFactory) createAction(cfg *config.Config, t *i18n.Translations) cli.ActionFunc {
return func(ctx context.Context, command *cli.Command) error {
emojiFlag := command.Bool("no-emoji")
if emojiFlag {
cfg.UseEmoji = false // Deshabilitar emojis si --no-emoji está presente
cfg.UseEmoji = false
} else {
cfg.UseEmoji = true // Habilitar emojis si --no-emoji no está presente
cfg.UseEmoji = true
}
count := command.Int("count")
if count < 1 || count > 10 {
Expand All @@ -80,7 +87,21 @@ func (f *SuggestCommandFactory) createAction(cfg *config.Config, t *i18n.Transla
}

fmt.Println(t.GetMessage("analyzing_changes", 0, nil))
suggestions, err := f.commitService.GenerateSuggestions(ctx, int(count))

issueNumber := command.Int("issue")
var suggestions []models.CommitSuggestion
var err error

if issueNumber > 0 {
msg := t.GetMessage("issue_including_context", 0, map[string]interface{}{
"Number": issueNumber,
})
fmt.Println(msg)
suggestions, err = f.commitService.GenerateSuggestionsWithIssue(ctx, count, issueNumber)
} else {
suggestions, err = f.commitService.GenerateSuggestions(ctx, count)
}

if err != nil {
msg := t.GetMessage("suggestion_generation_error", 0, map[string]interface{}{"Error": err})
return fmt.Errorf("%s", msg)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package suggest
package suggests_commits

import (
"context"
Expand All @@ -14,7 +14,6 @@ import (
"github.com/stretchr/testify/mock"
)

// Mock para CommitService
type MockCommitService struct {
mock.Mock
}
Expand All @@ -24,6 +23,11 @@ func (m *MockCommitService) GenerateSuggestions(ctx context.Context, count int)
return args.Get(0).([]models.CommitSuggestion), args.Error(1)
}

func (m *MockCommitService) GenerateSuggestionsWithIssue(ctx context.Context, count int, issueNumber int) ([]models.CommitSuggestion, error) {
args := m.Called(ctx, count, issueNumber)
return args.Get(0).([]models.CommitSuggestion), args.Error(1)
}

// Mock para CommitHandler
type MockCommitHandler struct {
mock.Mock
Expand All @@ -45,7 +49,7 @@ func setupTestEnv(t *testing.T) (*config.Config, *i18n.Translations, func()) {
PathFile: tmpConfigPath,
Language: "es",
UseEmoji: true,
SuggestionsCount: 3, // Añadido el valor por defecto
SuggestionsCount: 3,
}

translations, err := i18n.NewTranslations("es", "../../../i18n/locales")
Expand Down Expand Up @@ -85,7 +89,7 @@ func TestSuggestCommand(t *testing.T) {
cmd := factory.CreateCommand(translations, cfg)

// Act
err := cmd.Run(ctx, []string{"suggest"}) // Sin especificar count, usa el valor por defecto
err := cmd.Run(ctx, []string{"suggest"})

// Assert
assert.NoError(t, err)
Expand Down
1 change: 1 addition & 0 deletions internal/domain/models/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type (
Files []string
Diff string
TicketInfo *TicketInfo
IssueInfo *Issue
}

GitChange struct {
Expand Down
12 changes: 12 additions & 0 deletions internal/domain/models/issue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package models

type Issue struct {
ID int
Number int
Title string
Description string
State string
Labels []string
Author string
URL string
}
8 changes: 0 additions & 8 deletions internal/domain/models/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ type (
FileStats FileStatistics
}

Issue struct {
Number int
Title string
Labels []string
Author string
URL string
}

PullRequest struct {
Number int
Title string
Expand Down
4 changes: 4 additions & 0 deletions internal/domain/ports/commit_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package ports

import (
"context"

"github.com/Tomas-vilte/MateCommit/internal/domain/models"
)

type CommitService interface {
// GenerateSuggestions genera sugerencias de commit basadas en los cambios detectados
GenerateSuggestions(ctx context.Context, count int) ([]models.CommitSuggestion, error)
// GenerateSuggestionsWithIssue genera sugerencias considerando un issue específico
GenerateSuggestionsWithIssue(ctx context.Context, count int, issueNumber int) ([]models.CommitSuggestion, error)
}
1 change: 1 addition & 0 deletions internal/domain/ports/git_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type GitService interface {
GetLastTag(ctx context.Context) (string, error)
GetCommitCount(ctx context.Context) (int, error)
GetCommitsSinceTag(ctx context.Context, tag string) ([]models.Commit, error)
GetRecentCommitMessages(ctx context.Context, count int) (string, error)
CreateTag(ctx context.Context, version, message string) error
PushTag(ctx context.Context, version string) error
}
4 changes: 2 additions & 2 deletions internal/domain/ports/vcs_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ type VCSClient interface {
GetContributorsBetweenTags(ctx context.Context, previousTag, currentTag string) ([]string, error)
// GetFileStatsBetweenTags obtiene estadísticas de archivos entre dos tags
GetFileStatsBetweenTags(ctx context.Context, previousTag, currentTag string) (*models.FileStatistics, error)
// GetFileAtTag obtiene el contenido de un archivo en un tag específico
GetFileAtTag(ctx context.Context, tag, filepath string) (string, error)
// GetIssue obtiene información de un issue/ticket por su número
GetIssue(ctx context.Context, issueNumber int) (*models.Issue, error)
}
18 changes: 18 additions & 0 deletions internal/i18n/locales/active.en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ other = "Language (en, es)"
[suggest_no_emoji_flag_usage]
other = "Disable emojis"

[suggest_issue_flag_usage]
other = "Issue/ticket number to include context in commit"

[issue_detected_auto]
other = "🔍 Detected issue #{{.Number}}: {{.Title}}"

[issue_using_manual]
other = "📋 Using issue #{{.Number}}: {{.Title}}"

[issue_including_context]
other = "📋 Including context from issue #{{.Number}}"

[issue_vcs_init_error]
other = "⚠️ Could not initialize VCS client: {{.Error}}"

[issue_fetch_error]
other = "⚠️ Could not fetch issue #{{.Number}} information: {{.Error}}"

[no_staged_changes]
other = "❌ No staged changes to commit.\nUse 'git add' to stage your changes first"

Expand Down
18 changes: 18 additions & 0 deletions internal/i18n/locales/active.es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ other = "Idioma (en, es)"
[suggest_no_emoji_flag_usage]
other = "Desactivar emojis"

[suggest_issue_flag_usage]
other = "Número de issue/ticket para incluir contexto en el commit"

[issue_detected_auto]
other = "🔍 Detectado issue #{{.Number}}: {{.Title}}"

[issue_using_manual]
other = "📋 Usando issue #{{.Number}}: {{.Title}}"

[issue_including_context]
other = "📋 Incluyendo contexto del issue #{{.Number}}"

[issue_vcs_init_error]
other = "⚠️ No se pudo inicializar el cliente VCS: {{.Error}}"

[issue_fetch_error]
other = "⚠️ No se pudo obtener información del issue #{{.Number}}: {{.Error}}"

[no_staged_changes]
other = "❌ No hay cambios preparados para commitear.\nUsá 'git add' para preparar tus cambios primero"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ func (s *GeminiService) GenerateSuggestions(ctx context.Context, info models.Com
return nil, fmt.Errorf("%s", msg)
}

if info.IssueInfo != nil && info.IssueInfo.Number > 0 {
suggestions = s.ensureIssueReference(suggestions, info.IssueInfo.Number)
}

return suggestions, nil
}

Expand All @@ -85,12 +89,21 @@ func (s *GeminiService) generatePrompt(locale string, info models.CommitInfo, co
strings.Join(info.TicketInfo.Criteria, ", "))
}

issueInstructions := ""
if info.IssueInfo != nil && info.IssueInfo.Number > 0 {
num := info.IssueInfo.Number
issueInstructions = fmt.Sprintf(ai.GetIssueReferenceInstructions(locale), num, num, num, num, num, num, num, num)
} else {
issueInstructions = "No hay issue asociado, no incluyas referencias de issues en el título."
}

return fmt.Sprintf(promptTemplate,
count,
count,
formatChanges(info.Files),
info.Diff,
ticketInfo,
issueInstructions,
)
}

Expand Down Expand Up @@ -188,6 +201,12 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio
if collectingFiles {
if strings.HasPrefix(trimmedLine, "-") {
file := strings.TrimSpace(strings.TrimPrefix(trimmedLine, "-"))
if strings.Contains(file, "->") {
parts := strings.Split(file, "->")
if len(parts) > 1 {
file = strings.TrimSpace(parts[len(parts)-1])
}
}
suggestion.Files = append(suggestion.Files, file)
} else if trimmedLine == "" || strings.HasPrefix(trimmedLine, s.trans.GetMessage("gemini_service.explanation_prefix", 0, nil)) {
collectingFiles = false
Expand Down Expand Up @@ -276,3 +295,29 @@ func (s *GeminiService) parseSuggestionPart(part string) *models.CommitSuggestio

return suggestion
}

// ensureIssueReference asegura que todas las sugerencias incluyan la referencia al issue correcta
func (s *GeminiService) ensureIssueReference(suggestions []models.CommitSuggestion, issueNumber int) []models.CommitSuggestion {
issuePattern := regexp.MustCompile(`\(#\d+\)`)

for i := range suggestions {
title := suggestions[i].CommitTitle
title = strings.TrimSpace(title)

if strings.Contains(title, fmt.Sprintf("(#%d)", issueNumber)) ||
strings.Contains(title, fmt.Sprintf("fixes #%d", issueNumber)) ||
strings.Contains(title, fmt.Sprintf("closes #%d", issueNumber)) {
continue
}

if issuePattern.MatchString(title) {
title = issuePattern.ReplaceAllString(title, fmt.Sprintf("(#%d)", issueNumber))
suggestions[i].CommitTitle = title
continue
}

suggestions[i].CommitTitle = fmt.Sprintf("%s (#%d)", title, issueNumber)
}

return suggestions
}
Loading
Loading