2
0
Files
gitcaddy-server/routers/web/repo/ai.go
logikonline 61e835358c feat(actions-manager): add AI service integration for code review and issue triage
Integrate GitCaddy AI service with support for code review, issue triage, documentation generation, code explanation, and chat interface. Add AI client module with HTTP communication, configuration settings, API routes (web and REST), service layer, and UI templates for issue sidebar. Include comprehensive configuration options in app.example.ini for enabling/disabling features and service connection settings.
2026-01-19 11:06:39 -05:00

144 lines
4.1 KiB
Go

// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
issues_model "code.gitcaddy.com/server/v3/models/issues"
"code.gitcaddy.com/server/v3/modules/setting"
"code.gitcaddy.com/server/v3/modules/templates"
"code.gitcaddy.com/server/v3/services/context"
ai_service "code.gitcaddy.com/server/v3/services/ai"
)
// AIReviewPullRequest handles the AI review request for a pull request
func AIReviewPullRequest(ctx *context.Context) {
if !ai_service.IsEnabled() {
ctx.Flash.Error(ctx.Tr("repo.ai.service_unavailable"))
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + ctx.PathParam("index"))
return
}
if !setting.AI.EnableCodeReview {
ctx.Flash.Error(ctx.Tr("repo.ai.code_review_disabled"))
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + ctx.PathParam("index"))
return
}
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
ctx.ServerError("GetIssueByIndex", err)
return
}
if !issue.IsPull {
ctx.NotFound("Not a pull request", nil)
return
}
pr, err := issues_model.GetPullRequestByIssueID(ctx, issue.ID)
if err != nil {
ctx.ServerError("GetPullRequestByIssueID", err)
return
}
review, err := ai_service.ReviewPullRequest(ctx, pr)
if err != nil {
ctx.Flash.Error(ctx.Tr("repo.ai.review_failed", err.Error()))
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + ctx.PathParam("index"))
return
}
// Store the review result in session for display
ctx.Session.Set("ai_review_result", review)
ctx.Flash.Success(ctx.Tr("repo.ai.review_completed"))
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + ctx.PathParam("index"))
}
// AITriageIssue handles the AI triage request for an issue
func AITriageIssue(ctx *context.Context) {
if !ai_service.IsEnabled() {
ctx.Flash.Error(ctx.Tr("repo.ai.service_unavailable"))
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + ctx.PathParam("index"))
return
}
if !setting.AI.EnableIssueTriage {
ctx.Flash.Error(ctx.Tr("repo.ai.issue_triage_disabled"))
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + ctx.PathParam("index"))
return
}
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
ctx.ServerError("GetIssueByIndex", err)
return
}
triage, err := ai_service.TriageIssue(ctx, issue)
if err != nil {
ctx.Flash.Error(ctx.Tr("repo.ai.triage_failed", err.Error()))
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + ctx.PathParam("index"))
return
}
// Store the triage result in session for display
ctx.Session.Set("ai_triage_result", triage)
ctx.Flash.Success(ctx.Tr("repo.ai.triage_completed"))
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + ctx.PathParam("index"))
}
// AISuggestLabels handles the AI label suggestion request
func AISuggestLabels(ctx *context.Context) {
if !ai_service.IsEnabled() {
ctx.JSON(http.StatusServiceUnavailable, map[string]string{
"error": ctx.Tr("repo.ai.service_unavailable"),
})
return
}
issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
ctx.JSON(http.StatusNotFound, map[string]string{
"error": "Issue not found",
})
return
}
suggestions, err := ai_service.SuggestLabels(ctx, issue)
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]string{
"error": err.Error(),
})
return
}
ctx.JSON(http.StatusOK, suggestions)
}
// IsAIEnabled is a template helper to check if AI is enabled
func IsAIEnabled() bool {
return ai_service.IsEnabled()
}
// IsAICodeReviewEnabled checks if AI code review is enabled
func IsAICodeReviewEnabled() bool {
return ai_service.IsEnabled() && setting.AI.EnableCodeReview
}
// IsAIIssueTriageEnabled checks if AI issue triage is enabled
func IsAIIssueTriageEnabled() bool {
return ai_service.IsEnabled() && setting.AI.EnableIssueTriage
}
func init() {
// Register template functions
templates.RegisterTemplateFunc("IsAIEnabled", IsAIEnabled)
templates.RegisterTemplateFunc("IsAICodeReviewEnabled", IsAICodeReviewEnabled)
templates.RegisterTemplateFunc("IsAIIssueTriageEnabled", IsAIIssueTriageEnabled)
}