mesh/delivery merged: source.main moved to novox/mesh-sdk@1888d1d230b3
mesh/delivery-group group fix/fetch-reads-all merged: every member is merged
mesh/check pass ff81bdf8cc8f on 960d6c34d25e | unit 5815 run, 345 kept, 18 skipped | integration 5603 run, 640 kept, 29 skipped | over bound: unit, in…
The mirror of jschoubben/car-hunter on ace said only "git -C: error:": git writes a bare "error:" before the forge's message, and the reason kept the first non-empty line. forgekey.Said keeps every line that says something, leaves bare prefixes out, joins them and bounds them at 600 bytes; every git and ssh-keygen reason of buildstep and forgekey goes through it, and the mirror's commands are named by their verb, not by -C.
125 lines
4.5 KiB
Go
125 lines
4.5 KiB
Go
package buildstep
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
|
)
|
|
|
|
// Issue 890 C1 (ADR 0536 §2): a fetch through a bare mirror names the mirror in .git/objects/info/alternates, a
|
|
// plain file, and never links it.
|
|
func TestFetchCommitWithMirrorWritesAlternates(t *testing.T) {
|
|
mirror := t.TempDir()
|
|
ws := t.TempDir()
|
|
f := &fakeGit{}
|
|
// the fake's init does not create .git; make the objects directory as git init would.
|
|
if err := os.MkdirAll(filepath.Join(ws, ".git", "objects", "info"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err := FetchCommit(context.Background(), f.run, ws, "ssh://mesh-forge/novox/mesh-sdk.git", sha, "", WithMirror(mirror))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p := filepath.Join(ws, ".git", "objects", "info", "alternates")
|
|
b, err := os.ReadFile(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, want := strings.TrimSpace(string(b)), filepath.Join(mirror, "objects"); got != want {
|
|
t.Errorf("alternates %q, want %q", got, want)
|
|
}
|
|
if fi, err := os.Lstat(p); err != nil || !fi.Mode().IsRegular() {
|
|
t.Errorf("alternates is not a plain file: %v %v", fi, err)
|
|
}
|
|
// the alternates exist before the fetch runs
|
|
if len(f.calls) < 3 || !strings.Contains(f.calls[2], "fetch") {
|
|
t.Errorf("calls %v", f.calls)
|
|
}
|
|
}
|
|
|
|
func TestWithMirrorRefusesARelativeOrMissingMirror(t *testing.T) {
|
|
for _, m := range []string{"rel/mirror", filepath.Join(t.TempDir(), "absent")} {
|
|
f := &fakeGit{}
|
|
err := FetchCommit(context.Background(), f.run, t.TempDir(), "ssh://mesh-forge/novox/x.git", sha, "", WithMirror(m))
|
|
if err == nil || len(f.calls) != 0 {
|
|
t.Errorf("mirror %q: err %v, calls %v", m, err, f.calls)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUpdateMirrorInitsBareThenFetches(t *testing.T) {
|
|
mirror := filepath.Join(t.TempDir(), "mirror.git")
|
|
f := &fakeGit{}
|
|
if err := UpdateMirror(context.Background(), f.run, mirror, "ssh://mesh-forge/novox/x.git", sha, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
pm := "git -c credential.helper= -C " + mirror + " "
|
|
want := []string{
|
|
"git -c credential.helper= init -q --bare " + mirror,
|
|
pm + "remote add origin ssh://mesh-forge/novox/x.git",
|
|
pm + "fetch --no-tags origin " + sha,
|
|
pm + "cat-file -e " + sha + "^{commit}",
|
|
}
|
|
if strings.Join(f.calls, "\n") != strings.Join(want, "\n") {
|
|
t.Errorf("commands:\n%s\nwant:\n%s", strings.Join(f.calls, "\n"), strings.Join(want, "\n"))
|
|
}
|
|
}
|
|
|
|
func TestUpdateMirrorKeepsAnExistingMirrorAndFallsBackToTheRef(t *testing.T) {
|
|
mirror := t.TempDir() // exists: no init
|
|
if err := os.WriteFile(filepath.Join(mirror, "HEAD"), []byte("ref: refs/heads/main\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f := &fakeGit{}
|
|
f.rule = func(args string) (r forgekey.Ran) {
|
|
if strings.HasSuffix(args, "origin "+sha) {
|
|
r.Status = 1
|
|
r.Stderr = "not our ref"
|
|
}
|
|
return
|
|
}
|
|
if err := UpdateMirror(context.Background(), f.run, mirror, "ssh://mesh-forge/novox/x.git", sha, "refs/pull/3/head"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
all := strings.Join(f.calls, "\n")
|
|
if strings.Contains(all, "init") || strings.Contains(all, "remote add") || !strings.Contains(all, "fetch --no-tags origin refs/pull/3/head") {
|
|
t.Errorf("commands:\n%s", all)
|
|
}
|
|
}
|
|
|
|
func TestUpdateMirrorRefusesBeforeRunning(t *testing.T) {
|
|
f := &fakeGit{}
|
|
for _, c := range []struct{ remote, commit string }{
|
|
{"https://x/y.git", sha}, {"ssh://u@h/o/r.git", sha}, {"ssh://h/o/r.git", "abc"},
|
|
} {
|
|
if err := UpdateMirror(context.Background(), f.run, t.TempDir(), c.remote, c.commit, ""); err == nil {
|
|
t.Errorf("%v accepted", c)
|
|
}
|
|
}
|
|
if len(f.calls) != 0 {
|
|
t.Errorf("ran %v", f.calls)
|
|
}
|
|
}
|
|
|
|
// The forge's refusal reaches the reason in git's own words: the mirror of a repository its account cannot read said
|
|
// only "git -C: error:" (2026-10-26), since git writes a bare "error:" line before the forge's message.
|
|
func TestUpdateMirrorSaysTheForgesRefusal(t *testing.T) {
|
|
f := &fakeGit{}
|
|
f.rule = func(args string) (r forgekey.Ran) {
|
|
if strings.Contains(args, "fetch") {
|
|
r.Status = 128
|
|
r.Stderr = "error: \nerror: User: 22:nox-builder with Key: 30:mesh:ace.mesh-build-go is not authorized to read o/r.\nerror: \nfatal: Could not read from remote repository.\n"
|
|
}
|
|
return
|
|
}
|
|
err := UpdateMirror(context.Background(), f.run, filepath.Join(t.TempDir(), "m.git"), "ssh://mesh-forge/o/r.git", sha, "")
|
|
if err == nil || !strings.Contains(err.Error(), "nox-builder with Key: 30:mesh:ace.mesh-build-go is not authorized to read o/r.") ||
|
|
!strings.Contains(err.Error(), "Could not read from remote repository") || !strings.HasPrefix(err.Error(), "git fetch: ") {
|
|
t.Errorf("err = %v", err)
|
|
}
|
|
}
|