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

The OpenAPI document describes a pull's review states and attaching a look #5402

Merged opened this

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

Merged

scout/forge:scout/5382-the-openapi-document-describes-a-pull-s → main 4 commits fork

  • Merged. scout/5382-the-openapi-document-describes-a-pull-s was merged into main as abe1581.

Review

Sign in to review this change.
6 files changed +66 −3
src/contract/openapi/routes/getApiV1ReposOwnerNamePullsNumberReviewStates.ts added +8
@@ -0,0 +1,8 @@
1 import { REPO, type Route } from "../shared.ts";
2
3 export const route: Route = {
4 method: "get",
5 path: `${REPO}/pulls/{number}/review-states`,
6 summary: "List a pull's reviews, the verdicts (approved, changes_requested or commented), each with its body",
7 auth: false,
8 };
src/contract/openapi/routes/index.ts +3
@@ -101,6 +101,7 @@ export { route as getApiV1ReposOwnerNamePrompts } from "./getApiV1ReposOwnerName
101101 export { route as getApiV1ReposOwnerNamePulls } from "./getApiV1ReposOwnerNamePulls.ts";
102102 export { route as getApiV1ReposOwnerNamePullsNumber } from "./getApiV1ReposOwnerNamePullsNumber.ts";
103103 export { route as getApiV1ReposOwnerNamePullsNumberChecks } from "./getApiV1ReposOwnerNamePullsNumberChecks.ts";
104 export { route as getApiV1ReposOwnerNamePullsNumberReviewStates } from "./getApiV1ReposOwnerNamePullsNumberReviewStates.ts";
104105 export { route as getApiV1ReposOwnerNamePullsNumberReviews } from "./getApiV1ReposOwnerNamePullsNumberReviews.ts";
105106 export { route as getApiV1ReposOwnerNamePullsNumberThreads } from "./getApiV1ReposOwnerNamePullsNumberThreads.ts";
106107 export { route as getApiV1ReposOwnerNameReports } from "./getApiV1ReposOwnerNameReports.ts";
@@ -217,7 +218,9 @@ export { route as postApiV1ReposOwnerNamePulls } from "./postApiV1ReposOwnerName
217218 export { route as postApiV1ReposOwnerNamePullsNumberApproveHere } from "./postApiV1ReposOwnerNamePullsNumberApproveHere.ts";
218219 export { route as postApiV1ReposOwnerNamePullsNumberChecks } from "./postApiV1ReposOwnerNamePullsNumberChecks.ts";
219220 export { route as postApiV1ReposOwnerNamePullsNumberComments } from "./postApiV1ReposOwnerNamePullsNumberComments.ts";
221 export { route as postApiV1ReposOwnerNamePullsNumberLooks } from "./postApiV1ReposOwnerNamePullsNumberLooks.ts";
220222 export { route as postApiV1ReposOwnerNamePullsNumberMerge } from "./postApiV1ReposOwnerNamePullsNumberMerge.ts";
223 export { route as postApiV1ReposOwnerNamePullsNumberReviewStates } from "./postApiV1ReposOwnerNamePullsNumberReviewStates.ts";
221224 export { route as postApiV1ReposOwnerNamePullsNumberReviews } from "./postApiV1ReposOwnerNamePullsNumberReviews.ts";
222225 export { route as postApiV1ReposOwnerNamePullsNumberThreadsAnchorResolve } from "./postApiV1ReposOwnerNamePullsNumberThreadsAnchorResolve.ts";
223226 export { route as postApiV1ReposOwnerNamePullsNumberVariant } from "./postApiV1ReposOwnerNamePullsNumberVariant.ts";
src/contract/openapi/routes/postApiV1ReposOwnerNamePullsNumberLooks.ts added +18
@@ -0,0 +1,18 @@
1 import { REPO, type Route } from "../shared.ts";
2
3 export const route: Route = {
4 method: "post",
5 path: `${REPO}/pulls/{number}/looks`,
6 summary: "Attach a look to a pull: a base64 picture at a stated width with a line saying what it shows (rw scope); answers 201 with { id, width, says, by, commit, url }",
7 auth: true,
8 status: 201,
9 body: { width: "string", says: "string", image: "string" },
10 refusals: {
11 too_large: "the picture is over the size cap (413)",
12 not_open: "the pull is closed or merged (409)",
13 no_app: "the repository has no app to look at (409)",
14 bad_image: "`image` is not an acceptable picture (422)",
15 bad_note: "`says` is not acceptable (422)",
16 bad_width: "`width` is not one the forge takes (422)",
17 },
18 };
src/contract/openapi/routes/postApiV1ReposOwnerNamePullsNumberReviewStates.ts added +17
@@ -0,0 +1,17 @@
1 import { REPO, type Route } from "../shared.ts";
2
3 export const route: Route = {
4 method: "post",
5 path: `${REPO}/pulls/{number}/review-states`,
6 summary: "Submit a verdict on a pull (rw scope); answers 201 with the review; `comments` are line comments posted with it",
7 auth: true,
8 status: 201,
9 body: { state: "string", body: "string", comments: "array" },
10 refusals: {
11 invalid_state: "`state` is not approved, changes_requested or commented (422)",
12 invalid_comments: "`comments` is not a list of {path, line, side, body} (422)",
13 self_review: "you cannot approve your own pull (422)",
14 bad_anchor: "a comment's anchor is not in the diff; nothing was posted (422)",
15 too_many_lines: "the review carries more line comments than the cap (422)",
16 },
17 };
test/openapi-coverage.test.ts −3
@@ -28,7 +28,6 @@ const NOT_YET_DESCRIBED: readonly string[] = [
2828 "GET /api/v1/repos/{}/{}/labels",
2929 "GET /api/v1/repos/{}/{}/milestones",
3030 "GET /api/v1/repos/{}/{}/milestones/{}",
31 "GET /api/v1/repos/{}/{}/pulls/{}/review-states",
3231 "GET /api/v1/user",
3332 "GET /api/v1/user/assigned",
3433 "GET /api/v1/user/keys",
@@ -58,8 +57,6 @@ const NOT_YET_DESCRIBED: readonly string[] = [
5857 "POST /api/v1/repos/{}/{}/prompts/{}/run",
5958 "POST /api/v1/repos/{}/{}/proposal-tokens",
6059 "POST /api/v1/repos/{}/{}/pulls/{}/comments",
61 "POST /api/v1/repos/{}/{}/pulls/{}/looks",
62 "POST /api/v1/repos/{}/{}/pulls/{}/review-states",
6360 "POST /api/v1/repos/{}/{}/pulls/{}/variant",
6461 "POST /api/v1/repos/{}/{}/reports/{}/accept",
6562 "POST /api/v1/repos/{}/{}/reports/{}/dismiss",
test/openapi-oa-pull-review.test.ts added +20
@@ -0,0 +1,20 @@
1 /** A pull's review states and attaching a look are in the served OpenAPI document. */
2 import { expect, test } from "bun:test";
3 import { openapi } from "../src/contract/openapi.ts";
4
5 const R = "/api/v1/repos/{owner}/{name}/pulls/{number}";
6 type Op = { security?: unknown; responses?: Record<string, unknown>; requestBody?: unknown };
7
8 test("review-states and looks are described with their method, auth and refusals", () => {
9 const paths = openapi("http://x", "1").paths as Record<string, Record<string, Op>>;
10 expect(paths[`${R}/review-states`]?.get).toBeDefined();
11 const post = paths[`${R}/review-states`]?.post;
12 expect(post?.requestBody).toBeDefined();
13 expect(post?.responses?.["201"]).toBeDefined();
14 expect(JSON.stringify(post)).toContain("self_review");
15 const look = paths[`${R}/looks`]?.post;
16 expect(look?.requestBody).toBeDefined();
17 expect(look?.responses?.["201"]).toBeDefined();
18 expect(JSON.stringify(look)).toContain("not_open");
19 expect(paths[`${R}/looks`]?.get).toBeUndefined();
20 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs