cairn/internal/models/artifact.go

182 lines
4.7 KiB
Go

package models
import (
"context"
"encoding/json"
"fmt"
cairnapi "github.com/mattnite/cairn/internal/api"
"gorm.io/gorm"
)
type CreateArtifactParams struct {
RepositoryID uint
CommitID uint
BuildID *uint
CampaignID *uint
Type string
BlobKey string
BlobSize int64
CrashMessage *string
StackTrace *string
Tags json.RawMessage
Metadata json.RawMessage
}
func CreateArtifact(ctx context.Context, db *gorm.DB, p CreateArtifactParams) (*cairnapi.Artifact, error) {
if p.Tags == nil {
p.Tags = json.RawMessage("{}")
}
if p.Metadata == nil {
p.Metadata = json.RawMessage("{}")
}
a := &Artifact{
RepositoryID: p.RepositoryID,
CommitID: p.CommitID,
BuildID: p.BuildID,
CampaignID: p.CampaignID,
Type: p.Type,
BlobKey: p.BlobKey,
BlobSize: p.BlobSize,
CrashMessage: p.CrashMessage,
StackTrace: p.StackTrace,
Tags: p.Tags,
Metadata: p.Metadata,
}
if err := db.WithContext(ctx).Create(a).Error; err != nil {
return nil, fmt.Errorf("creating artifact: %w", err)
}
return enrichArtifact(ctx, db, *a)
}
func GetArtifact(ctx context.Context, db *gorm.DB, id uint) (*cairnapi.Artifact, error) {
a := &Artifact{}
if err := db.WithContext(ctx).First(a, id).Error; err != nil {
return nil, fmt.Errorf("getting artifact: %w", err)
}
return enrichArtifact(ctx, db, *a)
}
type ListArtifactsParams struct {
RepositoryID *uint
CommitSHA string
Type string
SignatureID *uint
CampaignID *uint
Limit int
Offset int
}
func ListArtifacts(ctx context.Context, db *gorm.DB, p ListArtifactsParams) ([]cairnapi.Artifact, int64, error) {
if p.Limit <= 0 {
p.Limit = 50
}
query := db.WithContext(ctx).Model(&Artifact{})
if p.RepositoryID != nil {
query = query.Where("repository_id = ?", *p.RepositoryID)
}
if p.Type != "" {
query = query.Where("type = ?", p.Type)
}
if p.SignatureID != nil {
query = query.Where("crash_signature_id = ?", *p.SignatureID)
}
if p.CampaignID != nil {
query = query.Where("campaign_id = ?", *p.CampaignID)
}
if p.CommitSHA != "" {
query = query.Joins("JOIN commits ON commits.id = artifacts.commit_id").Where("commits.sha = ?", p.CommitSHA)
}
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("counting artifacts: %w", err)
}
var dbArtifacts []Artifact
if err := query.Order("created_at DESC").Limit(p.Limit).Offset(p.Offset).Find(&dbArtifacts).Error; err != nil {
return nil, 0, fmt.Errorf("listing artifacts: %w", err)
}
artifacts := make([]cairnapi.Artifact, 0, len(dbArtifacts))
for _, m := range dbArtifacts {
a, err := enrichArtifact(ctx, db, m)
if err != nil {
return nil, 0, err
}
artifacts = append(artifacts, *a)
}
return artifacts, total, nil
}
func SearchArtifacts(ctx context.Context, db *gorm.DB, query string, limit, offset int) ([]cairnapi.Artifact, int64, error) {
if limit <= 0 {
limit = 50
}
q := db.WithContext(ctx).Model(&Artifact{}).Where(
"type ILIKE ? OR crash_message ILIKE ? OR stack_trace ILIKE ?",
"%"+query+"%", "%"+query+"%", "%"+query+"%",
)
var total int64
if err := q.Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("counting search results: %w", err)
}
var dbArtifacts []Artifact
if err := q.Order("created_at DESC").Limit(limit).Offset(offset).Find(&dbArtifacts).Error; err != nil {
return nil, 0, fmt.Errorf("searching artifacts: %w", err)
}
artifacts := make([]cairnapi.Artifact, 0, len(dbArtifacts))
for _, m := range dbArtifacts {
a, err := enrichArtifact(ctx, db, m)
if err != nil {
return nil, 0, err
}
artifacts = append(artifacts, *a)
}
return artifacts, total, nil
}
func enrichArtifact(ctx context.Context, db *gorm.DB, model Artifact) (*cairnapi.Artifact, error) {
repo := &Repository{}
if err := db.WithContext(ctx).First(repo, model.RepositoryID).Error; err != nil {
return nil, fmt.Errorf("loading artifact repository: %w", err)
}
commit := &Commit{}
if err := db.WithContext(ctx).First(commit, model.CommitID).Error; err != nil {
return nil, fmt.Errorf("loading artifact commit: %w", err)
}
artifact := artifactFromModel(model)
artifact.RepoName = repo.Name
artifact.CommitSHA = commit.SHA
return &artifact, nil
}
func artifactFromModel(m Artifact) cairnapi.Artifact {
return cairnapi.Artifact{
ID: m.ID,
RepositoryID: m.RepositoryID,
CommitID: m.CommitID,
BuildID: m.BuildID,
CampaignID: m.CampaignID,
CrashSignatureID: m.CrashSignatureID,
Type: m.Type,
BlobKey: m.BlobKey,
BlobSize: m.BlobSize,
CrashMessage: m.CrashMessage,
StackTrace: m.StackTrace,
Tags: m.Tags,
Metadata: m.Metadata,
CreatedAt: m.CreatedAt,
}
}