101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package forgejo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
cairnapi "github.com/mattnite/cairn/internal/api"
|
|
"github.com/rs/zerolog/log"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/mattnite/cairn/internal/models"
|
|
)
|
|
|
|
// Sync handles bidirectional state synchronization between Cairn and Forgejo.
|
|
type Sync struct {
|
|
Client *Client
|
|
DB *gorm.DB
|
|
}
|
|
|
|
// CreateIssueForCrashGroup creates a Forgejo issue for a new crash group.
|
|
func (s *Sync) CreateIssueForCrashGroup(ctx context.Context, group *cairnapi.CrashGroup, sampleTrace string) error {
|
|
if s.Client == nil {
|
|
return nil
|
|
}
|
|
|
|
repo, err := models.GetRepositoryByID(ctx, s.DB, group.RepositoryID)
|
|
if err != nil {
|
|
return fmt.Errorf("getting repository: %w", err)
|
|
}
|
|
|
|
body := fmt.Sprintf(`## Crash Group
|
|
|
|
**Fingerprint:** `+"`%s`"+`
|
|
**First seen:** %s
|
|
**Type:** %s
|
|
|
|
### Sample Stack Trace
|
|
|
|
`+"```"+`
|
|
%s
|
|
`+"```"+`
|
|
|
|
---
|
|
*Auto-created by [Cairn](/) — crash artifact aggregator*
|
|
`, group.Fingerprint, group.FirstSeenAt.Format("2006-01-02 15:04:05"), group.Title, sampleTrace)
|
|
|
|
issue, err := s.Client.CreateIssue(ctx, repo.Owner, repo.Name, CreateIssueRequest{
|
|
Title: "[Cairn] " + group.Title,
|
|
Body: body,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("creating issue: %w", err)
|
|
}
|
|
|
|
if err := s.DB.WithContext(ctx).
|
|
Model(&models.CrashGroup{}).
|
|
Where("id = ?", group.ID).
|
|
Update("forgejo_issue_id", issue.Number).Error; err != nil {
|
|
return err
|
|
}
|
|
issueURL := fmt.Sprintf("%s/%s/%s/issues/%d", strings.TrimRight(s.Client.BaseURL(), "/"), repo.Owner, repo.Name, issue.Number)
|
|
group.ForgejoIssueURL = &issueURL
|
|
return nil
|
|
}
|
|
|
|
// HandleIssueEvent processes a Forgejo issue webhook event for state sync.
|
|
func (s *Sync) HandleIssueEvent(ctx context.Context, event *WebhookEvent) error {
|
|
if event.Issue == nil {
|
|
return nil
|
|
}
|
|
|
|
// Only handle issues that start with [Cairn] prefix.
|
|
if !strings.HasPrefix(event.Issue.Title, "[Cairn] ") {
|
|
return nil
|
|
}
|
|
|
|
switch event.Action {
|
|
case "closed":
|
|
return s.DB.WithContext(ctx).
|
|
Model(&models.CrashGroup{}).
|
|
Where("forgejo_issue_id = ?", event.Issue.Number).
|
|
Update("status", "resolved").Error
|
|
case "reopened":
|
|
return s.DB.WithContext(ctx).
|
|
Model(&models.CrashGroup{}).
|
|
Where("forgejo_issue_id = ?", event.Issue.Number).
|
|
Update("status", "open").Error
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandlePushEvent processes a push webhook event for commit enrichment.
|
|
func (s *Sync) HandlePushEvent(ctx context.Context, event *WebhookEvent) {
|
|
if event.Repo == nil || event.After == "" {
|
|
return
|
|
}
|
|
log.Info().Str("repo", event.Repo.FullName).Str("sha", event.After[:8]).Msg("Push event")
|
|
}
|