Hash the root tree from the root's entries, since the forge names the commit (issue 1234)
mesh/repo-check head 75957fc3c006 merged into trunk e8c3448797c7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/merge-gate head 75957fc3c006 merged into trunk e8c3448797c7 — pass: group feat/delivery-parts composed: every machine composes with the change as it d…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792433168676870614 (novox/mesh-catalog at eda55ceb into main,…
mesh/delivery-group group feat/delivery-parts delivered: every member is delivered
mesh/repo-check head 75957fc3c006 merged into trunk e8c3448797c7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/merge-gate head 75957fc3c006 merged into trunk e8c3448797c7 — pass: group feat/delivery-parts composed: every machine composes with the change as it d…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792433168676870614 (novox/mesh-catalog at eda55ceb into main,…
mesh/delivery-group group feat/delivery-parts delivered: every member is delivered
The listing's top sha is the commit's, not the root tree's (seen live, novox/mesh-delivery at 7f61817), so gitea_commit_trees now computes the root tree as git does, from the entries without a slash. The query keys recursive and per_page stay in the allow-list: read flags only.
This commit is contained in:
@@ -4,7 +4,10 @@ import { createServer } from "node:http";
|
||||
|
||||
// Fixtures follow Gitea's GitTreeResponse as its API documents it (swagger: sha, url, tree[{path, mode, type, size,
|
||||
// sha, url}], truncated, page, total_count) and as the forge answers GET /repos/{o}/{r}/git/trees/{sha}; the entry
|
||||
// fields are those, with sha values written out (no live capture: the answer's shape is what matters here).
|
||||
// fields are those, with sha values written out. The live capture (1234/AC6): GET
|
||||
// /repos/novox/mesh-delivery/git/trees/7f61817 (non-recursive) answered the COMMIT's sha at the top, not the root
|
||||
// tree's; the root tree is computed from the root's own entries, as git does.
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
const COMMIT = "c".repeat(40);
|
||||
const h = (c: string) => c.repeat(40);
|
||||
@@ -25,6 +28,14 @@ const LISTING = [
|
||||
entry("modules/d/notes.md", "blob", h("b")),
|
||||
];
|
||||
|
||||
/** git's own hash of a tree from its entries (an independent restatement for the fixtures): mode without leading zero. */
|
||||
function gitTree(es: { path: string; type: string; sha: string; mode: string }[]): string {
|
||||
const ordered = es.map((e) => ({ ...e, key: e.path + (e.type === "tree" ? "/" : "") })).sort((a, b) => Buffer.compare(Buffer.from(a.key), Buffer.from(b.key)));
|
||||
const body = Buffer.concat(ordered.map((e) => Buffer.concat([Buffer.from(`${e.mode.replace(/^0+/, "")} ${e.path}\0`), Buffer.from(e.sha, "hex")])));
|
||||
return createHash("sha1").update(Buffer.concat([Buffer.from(`tree ${body.length}\0`), body])).digest("hex");
|
||||
}
|
||||
const ROOT = gitTree(LISTING.filter((e) => !e.path.includes("/")));
|
||||
|
||||
async function serve(pages: any[]) {
|
||||
const { GiteaClient } = await import("../client.ts");
|
||||
const asked: string[] = [];
|
||||
@@ -36,7 +47,7 @@ async function serve(pages: any[]) {
|
||||
return res.end("{}");
|
||||
}
|
||||
const page = Number(url.searchParams.get("page") ?? 1);
|
||||
res.end(JSON.stringify(pages[page - 1] ?? { sha: h("0"), tree: [], truncated: false, page, total_count: 0 }));
|
||||
res.end(JSON.stringify(pages[page - 1] ?? { sha: COMMIT, tree: [], truncated: false, page, total_count: 0 }));
|
||||
});
|
||||
await new Promise<void>((r) => server.listen(0, r));
|
||||
const client = new GiteaClient(`http://127.0.0.1:${(server.address() as any).port}`, "t");
|
||||
@@ -45,10 +56,10 @@ async function serve(pages: any[]) {
|
||||
|
||||
test("a commit's trees: the root and the tree of each directory holding a module.json", async () => {
|
||||
// 1234/AC1 and 1234/AC4
|
||||
const { client, server } = await serve([{ sha: h("0"), url: "u", tree: LISTING, truncated: false, page: 1, total_count: LISTING.length }]);
|
||||
const { client, server } = await serve([{ sha: COMMIT, url: "u", tree: LISTING, truncated: false, page: 1, total_count: LISTING.length }]);
|
||||
try {
|
||||
const got = await client.commitTrees("novox", "hq", COMMIT);
|
||||
assert.deepEqual(got, { root: h("0"), trees: { "": h("0"), "modules/a": h("4"), "modules/b/c": h("8") } });
|
||||
assert.deepEqual(got, { root: ROOT, trees: { "": ROOT, "modules/a": h("4"), "modules/b/c": h("8") } });
|
||||
} finally {
|
||||
server.close();
|
||||
}
|
||||
@@ -57,13 +68,13 @@ test("a commit's trees: the root and the tree of each directory holding a module
|
||||
test("a listing the forge pages is read page by page", async () => {
|
||||
// 1234/AC1
|
||||
const { client, server, asked } = await serve([
|
||||
{ sha: h("0"), tree: LISTING.slice(0, 5), truncated: true, page: 1, total_count: LISTING.length },
|
||||
{ sha: h("0"), tree: LISTING.slice(5, 9), truncated: true, page: 2, total_count: LISTING.length },
|
||||
{ sha: h("0"), tree: LISTING.slice(9), truncated: false, page: 3, total_count: LISTING.length },
|
||||
{ sha: COMMIT, tree: LISTING.slice(0, 5), truncated: true, page: 1, total_count: LISTING.length },
|
||||
{ sha: COMMIT, tree: LISTING.slice(5, 9), truncated: true, page: 2, total_count: LISTING.length },
|
||||
{ sha: COMMIT, tree: LISTING.slice(9), truncated: false, page: 3, total_count: LISTING.length },
|
||||
]);
|
||||
try {
|
||||
const got = await client.commitTrees("novox", "hq", COMMIT);
|
||||
assert.deepEqual(got.trees, { "": h("0"), "modules/a": h("4"), "modules/b/c": h("8") });
|
||||
assert.deepEqual(got.trees, { "": ROOT, "modules/a": h("4"), "modules/b/c": h("8") });
|
||||
assert.equal(asked.length, 3, `asked ${asked.join(" ")}`);
|
||||
} finally {
|
||||
server.close();
|
||||
@@ -72,7 +83,7 @@ test("a listing the forge pages is read page by page", async () => {
|
||||
|
||||
test("a listing the forge says is cut fails, naming the repository and the commit, and answers no trees", async () => {
|
||||
// 1234/AC2
|
||||
const { client, server } = await serve([{ sha: h("0"), tree: LISTING, truncated: true, page: 1, total_count: LISTING.length }]);
|
||||
const { client, server } = await serve([{ sha: COMMIT, tree: LISTING, truncated: true, page: 1, total_count: LISTING.length }]);
|
||||
try {
|
||||
await assert.rejects(client.commitTrees("novox", "hq", COMMIT), (err: Error) => {
|
||||
assert.match(err.message, /novox\/hq/);
|
||||
@@ -134,3 +145,29 @@ test("gitea_open_pulls says each pull request's head branch beside its head sha"
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("the root tree is git's hash of the root's own entries, never the listing's top sha (the commit's)", async () => {
|
||||
// 1234/AC6, from the live capture named in the header: novox/mesh-delivery at 7f61817.
|
||||
const commit = "7f618177d6773d8d2d2b9e0b10e13b85ec700c59";
|
||||
const listing = [
|
||||
entry("README.md", "blob", "a087d22cbcbecce42256315671ff7e4d6ca85a7c"),
|
||||
entry("merge-check.sh", "blob", "c4ef9a3dd6390b0edde7e4137095553897cecfb0"),
|
||||
entry("modules", "tree", "31c0abb312ee6ce4693a7aacdd8b3fba871d6cf3"),
|
||||
entry("modules/x", "tree", h("d")),
|
||||
entry("modules/x/module.json", "blob", h("e")),
|
||||
];
|
||||
const { GiteaClient } = await import("../client.ts");
|
||||
const server = createServer((req, res) => {
|
||||
res.end(JSON.stringify(new URL(req.url ?? "", "http://x").pathname.endsWith(`/git/trees/${commit}`)
|
||||
? { sha: commit, tree: listing, truncated: false, page: 1, total_count: listing.length } : {}));
|
||||
});
|
||||
await new Promise<void>((r) => server.listen(0, r));
|
||||
const client = new GiteaClient(`http://127.0.0.1:${(server.address() as any).port}`, "t");
|
||||
try {
|
||||
const got = await client.commitTrees("novox", "mesh-delivery", commit);
|
||||
assert.equal(got.root, "659bcaaac6c16972ec380267a4eba69d15558c26");
|
||||
assert.deepEqual(got.trees, { "modules/x": h("d") });
|
||||
} finally {
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user