Public: anyone can read this; the crew can change it.

On a fork, the page manifest offers its writer how it follows its parent: read it, take the parent's updates, propose its changes up #7864

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/7856-on-a-fork-the-page-manifest-offers-its-w → main 2 commits fork 1 thread · 1 unresolved

  • Merged. scout/7856-on-a-fork-the-page-manifest-offers-its-w was merged into main as b86853b.

Review

Sign in to review this change.
2 files changed +42 −0
src/actions/here.ts +16
@@ -383,5 +383,21 @@ function repoActions(
383383 out.push({ do: "merge a pull", http: `POST ${r}/pulls/{number}/merge` });
384384 if (canAdmin(db, repo, viewer))
385385 out.push({ do: "change settings", http: `PATCH ${r}` });
386 // How a native fork follows its parent: a writer's moves, the same rule
387 // `takeOrTell` and `proposeToParentForge` ask (`requireWriter`).
388 if (
389 repo.forkParentId !== null &&
390 repo.origin === null &&
391 canWrite(db, repo, viewer)
392 )
393 out.push(
394 { do: "read how it follows its parent", http: `GET ${r}/following`, mcp: "following" },
outdated

Add mcp: "following" here, "take_updates" on the take entry and "propose_to_parent_forge" on the propose entry, and spread ...unproven on the two writes if their actions require a verified email. Assert the mcp names in the test.

395 { do: "take the parent's updates", http: `POST ${r}/following/take`, mcp: "take_updates" },
396 {
397 do: "propose its changes to the parent",
398 http: `POST ${r}/following/propose-parent`,
399 mcp: "propose_to_parent_forge",
400 },
401 );
386402 return out;
387403 }
test/here-manifest.test.ts +26
@@ -193,6 +193,32 @@ describe("the manifest: what you can do here, as who you are", () => {
193193 expect(list).not.toContain("change settings");
194194 });
195195
196 test("a writer of a fork is offered how it follows its parent; a reader and a plain repository's writer are not", async () => {
197 const fork = await forkRepo(app, usersByName["wes"]!, getRepo(app.db, "acme", "game")!);
198 if (!fork.ok) throw new Error(String(fork.error));
199 const path = "/wes/game";
200 const moves = [
201 "read how it follows its parent",
202 "take the parent's updates",
203 "propose its changes to the parent",
204 ];
205 const { body } = await manifest(path, "wes");
206 for (const d of moves) expect(does(body)).toContain(d);
207 expect(body.actions.find((a: any) => a.do === moves[1]).http).toBe(
208 "POST /api/v1/repos/wes/game/following/take",
209 );
210 expect(moves.map((d) => body.actions.find((a: any) => a.do === d).mcp)).toEqual([
211 "following",
212 "take_updates",
213 "propose_to_parent_forge",
214 ]);
215 for (const who of ["carol", undefined])
216 for (const d of moves)
217 expect(does((await manifest(path, who)).body)).not.toContain(d);
218 for (const d of moves)
219 expect(does((await manifest("/acme/game", "wes")).body)).not.toContain(d);
220 });
221
196222 test("the owner also changes the settings", async () => {
197223 const { body } = await manifest("/acme/game", "alice");
198224 expect(body.you.as).toBe("owner");

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs