From 332aa75afd19c04083005e3c8792506ebee1db18 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 22 Oct 2026 11:09:48 +0200 Subject: [PATCH] mesh-config: read the pull request's commit from head_sha (issue 1826) --- .../cmd/mesh-config/pullforge_test.go | 35 +++++++++++++++++++ modules/mesh-config/cmd/mesh-config/pulls.go | 7 ++-- .../mesh-config/testdata/captured/README.md | 10 ++++++ .../get_pull_request_closed_merged_435.json | 17 +++++++++ .../captured/get_pull_request_open_434.json | 15 ++++++++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 modules/mesh-config/cmd/mesh-config/pullforge_test.go create mode 100644 modules/mesh-config/cmd/mesh-config/testdata/captured/README.md create mode 100644 modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_closed_merged_435.json create mode 100644 modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_open_434.json diff --git a/modules/mesh-config/cmd/mesh-config/pullforge_test.go b/modules/mesh-config/cmd/mesh-config/pullforge_test.go new file mode 100644 index 00000000..e3d7fab7 --- /dev/null +++ b/modules/mesh-config/cmd/mesh-config/pullforge_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "encoding/json" + "os" + "testing" +) + +// toolForge.Pull reads gitea_get_pull_request as the forge answers it (testdata/captured), bare or in the wrappings the +// runtime puts around a tool's answer. +func TestToolForgePullReadsTheCapturedAnswers(t *testing.T) { + for _, tc := range []struct { + file string + number int + open, merged bool + head string + }{ + {"get_pull_request_closed_merged_435.json", 435, false, true, "7b5f7f84acb73aaf8189200548ff69fd9aac04b2"}, + {"get_pull_request_open_434.json", 434, true, false, "c948f3a61c74257e6e3147effb396d9d6434f491"}, + } { + raw, err := os.ReadFile("testdata/captured/" + tc.file) + if err != nil { + t.Fatal(err) + } + content, _ := json.Marshal(map[string]any{"content": []map[string]any{{"type": "text", "text": string(raw)}}}) + ok, _ := json.Marshal(map[string]any{"ok": true, "output": "", "answer": json.RawMessage(raw)}) + for name, answer := range map[string]json.RawMessage{"bare": raw, "content list": content, "ok answer": ok} { + f := toolForge{ask: func(key string, body any) (json.RawMessage, error) { return answer, nil }} + open, merged, head, err := f.Pull("novox", "mesh-catalog", tc.number) + if err != nil || open != tc.open || merged != tc.merged || head != tc.head { + t.Errorf("%s (%s): open %v merged %v head %q, err %v", tc.file, name, open, merged, head, err) + } + } + } +} diff --git a/modules/mesh-config/cmd/mesh-config/pulls.go b/modules/mesh-config/cmd/mesh-config/pulls.go index c0b82ae0..82c73fd2 100644 --- a/modules/mesh-config/cmd/mesh-config/pulls.go +++ b/modules/mesh-config/cmd/mesh-config/pulls.go @@ -615,15 +615,14 @@ func (f toolForge) Pull(owner, repo string, number int) (bool, bool, string, err Pull struct { State string `json:"state"` Merged bool `json:"merged"` - Head struct { - SHA string `json:"sha"` - } `json:"head"` + // head is the branch name; the commit is head_sha (the forge module's mapPull). + HeadSHA string `json:"head_sha"` } `json:"pull"` } if err := json.Unmarshal(answer, &a); err != nil || a.Pull.State == "" { return false, false, "", fmt.Errorf("the forge's gitea_get_pull_request is not readable: %s", output) } - return a.Pull.State == "open", a.Pull.Merged, a.Pull.Head.SHA, nil + return a.Pull.State == "open", a.Pull.Merged, a.Pull.HeadSHA, nil } // unwrapAnswer reads a tool's answer whatever wraps it: the protocol's content list, or {output, ok, answer}. diff --git a/modules/mesh-config/cmd/mesh-config/testdata/captured/README.md b/modules/mesh-config/cmd/mesh-config/testdata/captured/README.md new file mode 100644 index 00000000..6aa6b702 --- /dev/null +++ b/modules/mesh-config/cmd/mesh-config/testdata/captured/README.md @@ -0,0 +1,10 @@ +Captured answers of the gitea module's `gitea_get_pull_request`, taken 2026-10-22 by fix-1826-catalog@shanks with +`mesh_call gitea.gitea_get_pull_request {"owner":"novox","repo":"mesh-catalog","number":N}` through the mesh MCP server. + +- get_pull_request_closed_merged_435.json: pull request 435, closed and merged. +- get_pull_request_open_434.json: pull request 434, open. + +Each file is the answer as the MCP server printed it. The runtime's own wrapping of the answer was not visible there +(the server prints the answer alone), so the tests also feed the files through the wrappings unwrapAnswer reads. +The `body` text is shortened to its first sentence and its Reviewed-by line (long prose of no interest here); every +other field is as returned. Note: `head` is the branch name, the commit is `head_sha`. diff --git a/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_closed_merged_435.json b/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_closed_merged_435.json new file mode 100644 index 00000000..baff81a7 --- /dev/null +++ b/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_closed_merged_435.json @@ -0,0 +1,17 @@ +{ + "pull": { + "base": "main", + "body": "Part of design 47's milestone R4c-9 (ADR 0487): the image build module. A container image becomes one more artifact kind the builder builds through a build module, like Go and Node: mesh-build-image builds rootless with buildah, a candidate's check publishes nothing, a trunk build publishes exactly one digest and its build key names the reference. build-agent keeps building and delivering every image until R4g; nothing the operator sees changes. One delivery group on branch `feat/r4c9-image-build` in mesh-catalog and mesh-delivery. After the delivery the lead assigns buildah and mesh-build-image to shanks and ace.\n\nReviewed-by: reviewer-r4c9@shanks at 7b5f7f84acb73aaf8189200548ff69fd9aac04b2", + "head": "feat/r4c9-image-build", + "head_sha": "7b5f7f84acb73aaf8189200548ff69fd9aac04b2", + "html_url": "http://127.0.0.1:20000/novox/mesh-catalog/pulls/435", + "merge_commit_sha": "5a6d082e8c55603e47f074deb96da80fc9240ab4", + "merged": true, + "merged_at": "2026-10-22T08:57:10Z", + "number": 435, + "state": "closed", + "title": "Add the image build module: buildah and mesh-build-image, rootless, publishing only from the trunk (issues 1702, 1703, 1704, 1707)", + "updated_at": "2026-10-22T08:57:10Z", + "user": "mesh-tools" + } +} diff --git a/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_open_434.json b/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_open_434.json new file mode 100644 index 00000000..f9975771 --- /dev/null +++ b/modules/mesh-config/cmd/mesh-config/testdata/captured/get_pull_request_open_434.json @@ -0,0 +1,15 @@ +{ + "pull": { + "base": "main", + "body": "Part of design 47's milestone R4d: n8n and the bus run pinned upstream images (ADR 0480).\n\nReviewed-by: reviewer-r4d@shanks at c948f3a61c74257e6e3147effb396d9d6434f491\n", + "head": "feat/r4d", + "head_sha": "c948f3a61c74257e6e3147effb396d9d6434f491", + "html_url": "http://127.0.0.1:20000/novox/mesh-catalog/pulls/434", + "merged": false, + "number": 434, + "state": "open", + "title": "n8n and the bus run their upstream images with the mesh's programs mounted (issues 1639, 1640, 1641, 1642, ADR 0480 §1-§3, §5-§8; ADR 0497 §5)", + "updated_at": "2026-10-22T08:57:45Z", + "user": "mesh-tools" + } +}