149 lines
4.3 KiB
Go
149 lines
4.3 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
cairnapi "github.com/mattnite/cairn/internal/api"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func GetOrCreateSignature(ctx context.Context, db *gorm.DB, repoID uint, fingerprint string, sampleTrace *string) (*cairnapi.CrashSignature, bool, error) {
|
|
sig := &CrashSignature{}
|
|
err := db.WithContext(ctx).Where("repository_id = ? AND fingerprint = ?", repoID, fingerprint).First(sig).Error
|
|
if err == nil {
|
|
sig.LastSeenAt = time.Now()
|
|
sig.OccurrenceCount++
|
|
if sig.SampleTrace == nil && sampleTrace != nil {
|
|
sig.SampleTrace = sampleTrace
|
|
}
|
|
if saveErr := db.WithContext(ctx).Save(sig).Error; saveErr != nil {
|
|
return nil, false, fmt.Errorf("updating signature: %w", saveErr)
|
|
}
|
|
out := crashSignatureFromModel(*sig)
|
|
return &out, false, nil
|
|
}
|
|
if err != gorm.ErrRecordNotFound {
|
|
return nil, false, fmt.Errorf("querying signature: %w", err)
|
|
}
|
|
|
|
now := time.Now()
|
|
sig = &CrashSignature{
|
|
RepositoryID: repoID,
|
|
Fingerprint: fingerprint,
|
|
SampleTrace: sampleTrace,
|
|
FirstSeenAt: now,
|
|
LastSeenAt: now,
|
|
OccurrenceCount: 1,
|
|
}
|
|
if err := db.WithContext(ctx).Create(sig).Error; err != nil {
|
|
return nil, false, fmt.Errorf("creating signature: %w", err)
|
|
}
|
|
out := crashSignatureFromModel(*sig)
|
|
return &out, true, nil
|
|
}
|
|
|
|
func CreateCrashGroup(ctx context.Context, db *gorm.DB, sigID, repoID uint, title string) (*cairnapi.CrashGroup, error) {
|
|
now := time.Now()
|
|
group := &CrashGroup{
|
|
CrashSignatureID: sigID,
|
|
RepositoryID: repoID,
|
|
Title: title,
|
|
Status: "open",
|
|
FirstSeenAt: now,
|
|
LastSeenAt: now,
|
|
}
|
|
if err := db.WithContext(ctx).Create(group).Error; err != nil {
|
|
return nil, fmt.Errorf("creating crash group: %w", err)
|
|
}
|
|
return enrichCrashGroup(ctx, db, *group)
|
|
}
|
|
|
|
func ListCrashGroups(ctx context.Context, db *gorm.DB, repoID *uint, status string, limit, offset int) ([]cairnapi.CrashGroup, int64, error) {
|
|
if limit <= 0 {
|
|
limit = 50
|
|
}
|
|
|
|
query := db.WithContext(ctx).Model(&CrashGroup{})
|
|
if repoID != nil {
|
|
query = query.Where("repository_id = ?", *repoID)
|
|
}
|
|
if status != "" {
|
|
query = query.Where("status = ?", status)
|
|
}
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("counting crash groups: %w", err)
|
|
}
|
|
|
|
var dbGroups []CrashGroup
|
|
if err := query.Order("last_seen_at DESC").Limit(limit).Offset(offset).Find(&dbGroups).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("listing crash groups: %w", err)
|
|
}
|
|
|
|
groups := make([]cairnapi.CrashGroup, 0, len(dbGroups))
|
|
for _, m := range dbGroups {
|
|
g, err := enrichCrashGroup(ctx, db, m)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
groups = append(groups, *g)
|
|
}
|
|
|
|
return groups, total, nil
|
|
}
|
|
|
|
func GetCrashGroup(ctx context.Context, db *gorm.DB, id uint) (*cairnapi.CrashGroup, error) {
|
|
group := &CrashGroup{}
|
|
if err := db.WithContext(ctx).First(group, id).Error; err != nil {
|
|
return nil, fmt.Errorf("getting crash group: %w", err)
|
|
}
|
|
return enrichCrashGroup(ctx, db, *group)
|
|
}
|
|
|
|
func enrichCrashGroup(ctx context.Context, db *gorm.DB, model CrashGroup) (*cairnapi.CrashGroup, error) {
|
|
repo := &Repository{}
|
|
if err := db.WithContext(ctx).First(repo, model.RepositoryID).Error; err != nil {
|
|
return nil, fmt.Errorf("loading crash group repository: %w", err)
|
|
}
|
|
sig := &CrashSignature{}
|
|
if err := db.WithContext(ctx).First(sig, model.CrashSignatureID).Error; err != nil {
|
|
return nil, fmt.Errorf("loading crash signature: %w", err)
|
|
}
|
|
|
|
group := crashGroupFromModel(model)
|
|
group.RepoName = repo.Name
|
|
group.Fingerprint = sig.Fingerprint
|
|
group.OccurrenceCount = sig.OccurrenceCount
|
|
return &group, nil
|
|
}
|
|
|
|
func crashSignatureFromModel(m CrashSignature) cairnapi.CrashSignature {
|
|
return cairnapi.CrashSignature{
|
|
ID: m.ID,
|
|
RepositoryID: m.RepositoryID,
|
|
Fingerprint: m.Fingerprint,
|
|
SampleTrace: m.SampleTrace,
|
|
FirstSeenAt: m.FirstSeenAt,
|
|
LastSeenAt: m.LastSeenAt,
|
|
OccurrenceCount: m.OccurrenceCount,
|
|
}
|
|
}
|
|
|
|
func crashGroupFromModel(m CrashGroup) cairnapi.CrashGroup {
|
|
return cairnapi.CrashGroup{
|
|
ID: m.ID,
|
|
RepositoryID: m.RepositoryID,
|
|
CrashSignatureID: m.CrashSignatureID,
|
|
Title: m.Title,
|
|
Status: m.Status,
|
|
ForgejoIssueID: m.ForgejoIssueID,
|
|
FirstSeenAt: m.FirstSeenAt,
|
|
LastSeenAt: m.LastSeenAt,
|
|
CreatedAt: m.CreatedAt,
|
|
UpdatedAt: m.UpdatedAt,
|
|
}
|
|
}
|