Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115package pulls
import ( "encoding/json" "fmt" "net/http" "slices" "time"
indigoxrpc "github.com/bluesky-social/indigo/xrpc"
"tangled.org/core/api/tangled" "tangled.org/core/appview/db" "tangled.org/core/appview/models" "tangled.org/core/hostutil" "tangled.org/core/types")
// spindle upgrades may change how a commit is resolved and hashed (even if very rare...)const ( workflowCacheSize = 4096 workflowCacheTTL = time.Hour)
func (s *Pulls) describeWorkflowAt(r *http.Request, f *models.Repo, sha, sourceRepo string) (*tangled.CiDescribeWorkflowDefinition_Output, error) { key := fmt.Sprintf("%s|%s|%s|%s", f.Spindle, f.RepoDid, sha, sourceRepo) if cached, ok := s.workflowDescCache.Get(key); ok { return cached, nil }
spindleUrl, err := hostutil.EnsureHttpScheme(f.Spindle) if err != nil { return nil, err } client := &indigoxrpc.Client{Host: spindleUrl} out, err := tangled.CiDescribeWorkflowDefinition(r.Context(), client, f.RepoDid, sha, sourceRepo) if err != nil { return nil, err }
s.workflowDescCache.Add(key, out) return out, nil}
// returns the merge-base of the pull's source and target branches.//// older rounds resolve it live on the fork's knot, which tracks the// target branch as refs/hidden/<source>/<target>.func (s *Pulls) mergeBase(r *http.Request, pull *models.Pull) (string, error) { if mb := pull.LatestSubmission().MergeBase; mb != "" { return mb, nil }
sourceBranch := pull.PullSource.Branch hiddenRef := fmt.Sprintf("hidden/%s/%s", sourceBranch, pull.TargetBranch)
key := fmt.Sprintf("%s|%s|%s", pull.PullSource.RepoDid, sourceBranch, pull.TargetBranch) if cached, ok := s.mergeBaseCache.Get(key); ok { return cached, nil }
forkRepo, err := db.GetRepoByDid(s.db, pull.PullSource.RepoDid.String()) if err != nil { return "", fmt.Errorf("resolving fork repo: %w", err) } compareBytes, err := tangled.RepoCompare(r.Context(), s.knotClient(forkRepo.Knot), forkRepo.RepoIdentifier(), hiddenRef, sourceBranch) if err != nil { return "", fmt.Errorf("comparing %s...%s: %w", hiddenRef, sourceBranch, err) } var comparison types.RepoFormatPatchResponse if err := json.Unmarshal(compareBytes, &comparison); err != nil { return "", fmt.Errorf("decoding comparison: %w", err) } if comparison.MergeBase == "" { return "", fmt.Errorf("no merge base between %s and %s", hiddenRef, sourceBranch) }
s.mergeBaseCache.Add(key, comparison.MergeBase) return comparison.MergeBase, nil}
// compares the spindle's workflow-definition fingerprints at the// pull head and its merge-base with the target branch.func (s *Pulls) workflowChangeFromSpindle(r *http.Request, f *models.Repo, pull *models.Pull) (bool, []string, error) { sourceRepo := pull.PullSource.RepoDid.String()
head, err := s.describeWorkflowAt(r, f, pull.LatestSha(), sourceRepo) if err != nil { return false, nil, err } // a definition not derived from the repo cannot change between commits if !head.Derived { return false, nil, nil }
baseSha, err := s.mergeBase(r, pull) if err != nil { return false, nil, err } base, err := s.describeWorkflowAt(r, f, baseSha, sourceRepo) if err != nil { return false, nil, err } if !base.Derived { return false, nil, nil } if head.Hash != nil && base.Hash != nil && *head.Hash == *base.Hash { return false, nil, nil }
names := slices.Concat(head.Workflows, base.Workflows) slices.Sort(names) return true, slices.Compact(names), nil}