package check import ( "context" "errors" "fmt" "regexp" "slices" "git.novox.be/novox/mesh-sdk/go/delivery" ) var digest64 = regexp.MustCompile(`^[0-9a-f]{64}$`) // PreviewOf is what the fetch steps said of a pull request's head merged onto its trunk head, as the value of a previews // key (ADR 0484 clause 3): the merge commit and, for each module directory the fetches named with a manifest, its tree, the // digest of its manifest, the hashes of its lock files and its named paths' objects (ADR 0499 clause 2). The fetches of the repository's build modules merge the same // trees; the first one's merge commit is kept. A module directory with no tree or no manifest digest is left out, so the // indexer gives its module no fingerprint and says why. A head that does not merge has a preview of the files in conflict // alone, so the indexer says the candidate's modules have no fingerprint because it does not merge (issue 1445). It // answers false when no fetch was made. func PreviewOf(p Pull, fetched []Fetched) (delivery.Preview, bool) { var merge string var conflicts []string mods := map[string]delivery.PreviewModule{} for _, f := range fetched { if len(f.Conflicts) > 0 { conflicts = append(conflicts, f.Conflicts...) } } if len(conflicts) > 0 { slices.Sort(conflicts) return delivery.Preview{Repository: p.Repository, Head: p.Head, Trunk: p.Trunk, Conflicts: slices.Compact(conflicts)}, true } for _, f := range fetched { if f.Merge == "" { continue } if merge == "" { merge = f.Merge } for dir, t := range f.Trees { if t.Tree == "" || !digest64.MatchString(t.Manifest) { continue } mods[dir] = delivery.PreviewModule{Tree: t.Tree, Manifest: t.Manifest, Locks: t.Locks, Paths: t.Paths} } } if merge == "" { return delivery.Preview{}, false } pv := delivery.Preview{Repository: p.Repository, Head: p.Head, Trunk: p.Trunk, Merge: merge} if len(mods) > 0 { pv.Modules = mods } return pv, true } // writePreview writes the preview of a pull request by a create: one writer per key, and the same head on the same trunk // head merges to the same trees, so a key that exists stands. A head that did not merge has no preview. A failure is said // and does not fail the check: the preview is for the indexer's fingerprints, not for the verdict. func (j *Examiner) writePreview(ctx context.Context, p Pull, fetched []Fetched) { if j.Previews == nil { return } pv, ok := PreviewOf(p, fetched) if !ok { return } key, err := delivery.PreviewKey(p.Repository, p.Head, p.Trunk) if err == nil { var data []byte if data, err = delivery.EncodePreview(pv); err == nil { _, err = j.Previews.Create(ctx, key, data) if errors.Is(err, ErrConflict) { return } if err == nil && j.Announce != nil { j.Announce(ctx, EventPreviewWritten, key) } } } if err != nil { j.logf("%s#%d: the preview cannot be written: %v", p.Repository, p.Number, fmt.Errorf("%w", err)) } }