feat: gitea client
This commit is contained in:
31
internal/gitadapters/baseadapter/rest.go
Normal file
31
internal/gitadapters/baseadapter/rest.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package baseadapter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Rest struct {
|
||||
baseURL string
|
||||
bearerToken string
|
||||
}
|
||||
|
||||
func (b *Rest) createRequest(method string, body io.Reader, path ...string) (r *http.Request, err error) {
|
||||
target, err := url.JoinPath(b.baseURL, path...)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("can not parse path: %w", err)
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(method, target, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.bearerToken != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+b.bearerToken)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/pierre"
|
||||
)
|
||||
|
||||
type BitbucketAdapter struct {
|
||||
@@ -36,3 +38,9 @@ func (b *BitbucketAdapter) GetDiff(projectKey, repositorySlug string, pullReques
|
||||
diff = response.Body
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BitbucketAdapter) AddComment(projectKey, repositorySlug string, pullRequestID int, comment pierre.Comment) error {
|
||||
fmt.Printf("[MOCK BITBUCKET] Adding comment to PR %s/%s #%d: %s at %s:%d\n",
|
||||
projectKey, repositorySlug, pullRequestID, comment.Message, comment.File, comment.Line)
|
||||
return nil
|
||||
}
|
||||
|
||||
46
internal/gitadapters/gitea/adapter.go
Normal file
46
internal/gitadapters/gitea/adapter.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/pierre"
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
type Adapter struct {
|
||||
client *gitea.Client
|
||||
}
|
||||
|
||||
func New(baseURL, token string) (*Adapter, error) {
|
||||
client, err := gitea.NewClient(baseURL, gitea.SetToken(token))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Adapter{
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *Adapter) GetDiff(owner, repo string, prID int) (io.Reader, error) {
|
||||
diff, _, err := g.client.GetPullRequestDiff(owner, repo, int64(prID), gitea.PullRequestDiffOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(diff), nil
|
||||
}
|
||||
|
||||
func (g *Adapter) AddComment(owner, repo string, prID int, comment pierre.Comment) error {
|
||||
opts := gitea.CreatePullReviewOptions{
|
||||
State: gitea.ReviewStateComment,
|
||||
Comments: []gitea.CreatePullReviewComment{
|
||||
{
|
||||
Path: comment.File,
|
||||
Body: comment.Message,
|
||||
NewLineNum: int64(comment.Line),
|
||||
},
|
||||
},
|
||||
}
|
||||
_, _, err := g.client.CreatePullReview(owner, repo, int64(prID), opts)
|
||||
return err
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package gitadapters
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"bitbucket.bit.admin.ch/scm/~u80859501/pierre-bot/internal/chatter"
|
||||
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/chatter"
|
||||
)
|
||||
|
||||
type Comment struct {
|
||||
@@ -14,28 +14,24 @@ type Comment struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type ChatAdapter interface {
|
||||
GenerateStructured(ctx context.Context, messages []chatter.Message, target interface{}) error
|
||||
}
|
||||
|
||||
func JudgePR(ctx context.Context, chat ChatAdapter, diff io.Reader) (comments []Comment, err error) {
|
||||
func (s *Service) judgePR(ctx context.Context, diff io.Reader) (comments []Comment, err error) {
|
||||
diffBytes, err := io.ReadAll(diff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read diff: %w", err)
|
||||
}
|
||||
err = chat.GenerateStructured(ctx, []chatter.Message{
|
||||
err = s.chat.GenerateStructured(ctx, []chatter.Message{
|
||||
{
|
||||
Role: chatter.RoleSystem,
|
||||
Content: `
|
||||
You are a very strict senior software architect.
|
||||
You review **only** newly added or modified lines in a unified diff (lines prefixed with “+”), together with the immediate hunk context.
|
||||
You review **only** newly added or modified lines in a unified diff, together with the immediate hunk context.
|
||||
You do **not** report issues that appear **solely** in deleted lines (“-”) or that have already been fixed by the change.
|
||||
No comments are made on pure formatting/whitespace changes or reordering that does not alter the program’s behavior.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Role: chatter.RoleUser,
|
||||
Content: fmt.Sprintf("Hello please review my PR.\n Here is the git diff of it: %s", string(diffBytes)),
|
||||
Content: fmt.Sprintf("Hello please review my PR. Write comments where improvements are necessary in new lines.\n Here is the git diff of it: %s", string(diffBytes)),
|
||||
},
|
||||
}, &comments)
|
||||
|
||||
|
||||
29
internal/pierre/resource.go
Normal file
29
internal/pierre/resource.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package pierre
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/chatter"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
git GitAdapter
|
||||
chat ChatAdapter
|
||||
}
|
||||
|
||||
func New(chat ChatAdapter, git GitAdapter) *Service {
|
||||
return &Service{
|
||||
git: git,
|
||||
chat: chat,
|
||||
}
|
||||
}
|
||||
|
||||
type GitAdapter interface {
|
||||
GetDiff(owner, repo string, prID int) (io.Reader, error)
|
||||
AddComment(owner, repo string, prID int, comment Comment) error
|
||||
}
|
||||
|
||||
type ChatAdapter interface {
|
||||
GenerateStructured(ctx context.Context, messages []chatter.Message, target interface{}) error
|
||||
}
|
||||
34
internal/pierre/review.go
Normal file
34
internal/pierre/review.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package pierre
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func (s *Service) MakeReview(ctx context.Context, organisation string, repo string, prID int) error {
|
||||
// Fetch Diff using positional args from shared RepoArgs
|
||||
diff, err := s.git.GetDiff(organisation, repo, prID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching diff: %w", err)
|
||||
}
|
||||
|
||||
// Run Logic
|
||||
comments, err := s.judgePR(ctx, diff)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error judging PR: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Analysis complete. Found %d issues.\n---\n", len(comments))
|
||||
|
||||
for _, c := range comments {
|
||||
fmt.Printf("File: %s\nLine: %d\nMessage: %s\n%s\n",
|
||||
c.File, c.Line, c.Message, "---")
|
||||
|
||||
if err := s.git.AddComment(organisation, repo, prID, c); err != nil {
|
||||
log.Printf("Failed to add comment: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user