Public: anyone can read this; the crew can change it.
The OpenAPI document describes labels made and removed, a commit's check, and a file read by path #5175
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/5113-the-openapi-document-describes-labels-ma → main 5 commits fork
7 files
changed +34
−4
src/contract/openapi/routes/deleteApiV1ReposOwnerNameLabelsId.ts added +3
| @@ -0,0 +1,3 @@ | ||
| 1 | import { REPO, type Route } from "../shared.ts"; | |
| 2 | ||
| 3 | export const route: Route = { method: "delete", path: `${REPO}/labels/{id}`, summary: "Remove a label by id (admin scope, repository admin); answers 204 with no body, 404 when the repository has no such label", auth: true, status: 204 }; |
src/contract/openapi/routes/getApiV1ReposOwnerNameCommitsOidCheck.ts added +3
| @@ -0,0 +1,3 @@ | ||
| 1 | import { REPO, type Route } from "../shared.ts"; | |
| 2 | ||
| 3 | export const route: Route = { method: "get", path: `${REPO}/commits/{oid}/check`, summary: "The default branch's check of a full 40-hex commit id, never cached: { commit, checkedCommit, state, runId, summary, finishedAt }; state is ok, failed, pending, superseded or none; 404 for a short id, an unknown commit or a repository you cannot read", auth: false }; |
src/contract/openapi/routes/getApiV1ReposOwnerNameContentsPath.ts added +3
| @@ -0,0 +1,3 @@ | ||
| 1 | import { REPO, type Route } from "../shared.ts"; | |
| 2 | ||
| 3 | export const route: Route = { method: "get", path: `${REPO}/contents/{path}`, summary: "Read a path at `ref` (default: the default branch): a directory answers { type: dir, ref, path, entries }, a file { type: file, ref, path, size, encoding, content } (utf-8, or base64 for binary); a file over 5 MB answers 413 { type: file, tooLarge, size }; 404 for an unsafe ref or path or one that is missing", auth: false, query: { ref: "string" } }; |
src/contract/openapi/routes/index.ts +4
| @@ -15,6 +15,7 @@ export { route as deleteApiV1ReposOwnerNameCrewUsername } from "./deleteApiV1Rep | ||
| 15 | 15 | export { route as deleteApiV1ReposOwnerNameEgressGrants } from "./deleteApiV1ReposOwnerNameEgressGrants.ts"; |
| 16 | 16 | export { route as deleteApiV1ReposOwnerNameHooksId } from "./deleteApiV1ReposOwnerNameHooksId.ts"; |
| 17 | 17 | export { route as deleteApiV1ReposOwnerNameIssuesNumberDependenciesBlocker } from "./deleteApiV1ReposOwnerNameIssuesNumberDependenciesBlocker.ts"; |
| 18 | export { route as deleteApiV1ReposOwnerNameLabelsId } from "./deleteApiV1ReposOwnerNameLabelsId.ts"; | |
| 18 | 19 | export { route as deleteApiV1ReposOwnerNameMilestonesNumberWatch } from "./deleteApiV1ReposOwnerNameMilestonesNumberWatch.ts"; |
| 19 | 20 | export { route as deleteApiV1ReposOwnerNamePromptsId } from "./deleteApiV1ReposOwnerNamePromptsId.ts"; |
| 20 | 21 | export { route as deleteApiV1ReposOwnerNamePullsNumberHold } from "./deleteApiV1ReposOwnerNamePullsNumberHold.ts"; |
| @@ -77,7 +78,9 @@ export { route as getApiV1ReposOwnerNameAppProductionOpen } from "./getApiV1Repo | ||
| 77 | 78 | export { route as getApiV1ReposOwnerNameBranches } from "./getApiV1ReposOwnerNameBranches.ts"; |
| 78 | 79 | export { route as getApiV1ReposOwnerNameCommits } from "./getApiV1ReposOwnerNameCommits.ts"; |
| 79 | 80 | export { route as getApiV1ReposOwnerNameCommitsOid } from "./getApiV1ReposOwnerNameCommitsOid.ts"; |
| 81 | export { route as getApiV1ReposOwnerNameCommitsOidCheck } from "./getApiV1ReposOwnerNameCommitsOidCheck.ts"; | |
| 80 | 82 | export { route as getApiV1ReposOwnerNameContents } from "./getApiV1ReposOwnerNameContents.ts"; |
| 83 | export { route as getApiV1ReposOwnerNameContentsPath } from "./getApiV1ReposOwnerNameContentsPath.ts"; | |
| 81 | 84 | export { route as getApiV1ReposOwnerNameCrew } from "./getApiV1ReposOwnerNameCrew.ts"; |
| 82 | 85 | export { route as getApiV1ReposOwnerNameDecisions } from "./getApiV1ReposOwnerNameDecisions.ts"; |
| 83 | 86 | export { route as getApiV1ReposOwnerNameEgressGrants } from "./getApiV1ReposOwnerNameEgressGrants.ts"; |
| @@ -208,6 +211,7 @@ export { route as postApiV1ReposOwnerNameIssues } from "./postApiV1ReposOwnerNam | ||
| 208 | 211 | export { route as postApiV1ReposOwnerNameIssuesNumberComments } from "./postApiV1ReposOwnerNameIssuesNumberComments.ts"; |
| 209 | 212 | export { route as postApiV1ReposOwnerNameIssuesNumberDependencies } from "./postApiV1ReposOwnerNameIssuesNumberDependencies.ts"; |
| 210 | 213 | export { route as postApiV1ReposOwnerNameIssuesNumberPrivate } from "./postApiV1ReposOwnerNameIssuesNumberPrivate.ts"; |
| 214 | export { route as postApiV1ReposOwnerNameLabels } from "./postApiV1ReposOwnerNameLabels.ts"; | |
| 211 | 215 | export { route as postApiV1ReposOwnerNameMakeItYours } from "./postApiV1ReposOwnerNameMakeItYours.ts"; |
| 212 | 216 | export { route as postApiV1ReposOwnerNameOriginReconnect } from "./postApiV1ReposOwnerNameOriginReconnect.ts"; |
| 213 | 217 | export { route as postApiV1ReposOwnerNamePlan } from "./postApiV1ReposOwnerNamePlan.ts"; |
src/contract/openapi/routes/postApiV1ReposOwnerNameLabels.ts added +3
| @@ -0,0 +1,3 @@ | ||
| 1 | import { REPO, type Route } from "../shared.ts"; | |
| 2 | ||
| 3 | export const route: Route = { method: "post", path: `${REPO}/labels`, summary: "Make a label (admin scope, repository admin); `color` is six hex digits and defaults to 6b7280; answers 201 with { id, name, color }", auth: true, body: { name: "string", color: "string" }, status: 201, refusals: { invalid: "422: the name is empty or the color is not six hex digits", taken: "422: a label of that name exists (any case)" } }; |
test/openapi-coverage.test.ts −4
| @@ -9,7 +9,6 @@ import { ROUTES } from "../src/contract/openapi.ts"; | ||
| 9 | 9 | */ |
| 10 | 10 | const NOT_YET_DESCRIBED: readonly string[] = [ |
| 11 | 11 | "DELETE /api/v1/orgs/{}/teams/{}/members/{}", |
| 12 | "DELETE /api/v1/repos/{}/{}/labels/{}", | |
| 13 | 12 | "DELETE /api/v1/user/keys/{}", |
| 14 | 13 | "DELETE /api/v1/user/origins/{}", |
| 15 | 14 | "DELETE /api/v1/user/pins/{}/{}", |
| @@ -23,8 +22,6 @@ const NOT_YET_DESCRIBED: readonly string[] = [ | ||
| 23 | 22 | "GET /api/v1/orgs/{}/teams", |
| 24 | 23 | "GET /api/v1/orgs/{}/teams/{}/members", |
| 25 | 24 | "GET /api/v1/repos/{}/{}/app/{}/open", |
| 26 | "GET /api/v1/repos/{}/{}/commits/{}/check", | |
| 27 | "GET /api/v1/repos/{}/{}/contents/{}", | |
| 28 | 25 | "GET /api/v1/repos/{}/{}/labels", |
| 29 | 26 | "GET /api/v1/repos/{}/{}/milestones", |
| 30 | 27 | "GET /api/v1/repos/{}/{}/milestones/{}", |
| @@ -53,7 +50,6 @@ const NOT_YET_DESCRIBED: readonly string[] = [ | ||
| 53 | 50 | "POST /api/v1/asks/proposal/{}/{}", |
| 54 | 51 | "POST /api/v1/feed/chips", |
| 55 | 52 | "POST /api/v1/repos/{}/{}/issues/{}/dependencies/{}/confirm", |
| 56 | "POST /api/v1/repos/{}/{}/labels", | |
| 57 | 53 | "POST /api/v1/repos/{}/{}/milestones/{}/limb", |
| 58 | 54 | "POST /api/v1/repos/{}/{}/prompts/{}/run", |
| 59 | 55 | "POST /api/v1/repos/{}/{}/proposal-tokens", |
test/openapi.test.ts +18
| @@ -429,6 +429,24 @@ test("the origin applications are described, and a client secret is written, nev | ||
| 429 | 429 | expect(JSON.stringify(add.responses["201"])).not.toContain("clientSecret"); |
| 430 | 430 | }); |
| 431 | 431 | |
| 432 | test("labels made and removed, a commit's check and a file read by path are described", () => { | |
| 433 | const doc = openapi("https://f.test", "1") as any; | |
| 434 | const R = "/api/v1/repos/{owner}/{name}"; | |
| 435 | const make = doc.paths[`${R}/labels`].post; | |
| 436 | expect(make.security).toBeDefined(); | |
| 437 | expect(Object.keys(make.requestBody.content["application/json"].schema.properties)).toEqual(["name", "color"]); | |
| 438 | expect(make.responses["201"]).toBeDefined(); | |
| 439 | const del = doc.paths[`${R}/labels/{id}`].delete; | |
| 440 | expect(del.security).toBeDefined(); | |
| 441 | expect(del.responses["204"]).toBeDefined(); | |
| 442 | const check = doc.paths[`${R}/commits/{oid}/check`].get; | |
| 443 | expect(check.security).toBeUndefined(); | |
| 444 | expect(check.parameters.find((p: any) => p.name === "oid").in).toBe("path"); | |
| 445 | const read = doc.paths[`${R}/contents/{path}`].get; | |
| 446 | expect(read.security).toBeUndefined(); | |
| 447 | expect(read.parameters.map((p: any) => p.name)).toEqual(["owner", "name", "path", "ref"]); | |
| 448 | }); | |
| 449 | ||
| 432 | 450 | test("the feed, chips and asks routes are described, and the bulk default is a preview", () => { |
| 433 | 451 | const doc = openapi("https://f.test", "1") as any; |
| 434 | 452 | const want: Record<string, string[]> = { |
new above
offline