87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
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 and the hashes of its lock files. 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}
|
|
}
|
|
}
|
|
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))
|
|
}
|
|
}
|