feat(cli): add GraphQL support and sync-project-fields script for Project field reconciliation

This commit is contained in:
Prad Nukala
2026-08-27 15:46:17 -04:00
parent fe2a7bb4e9
commit c5f3c95fcc
2 changed files with 275 additions and 3 deletions
+23 -3
View File
@@ -1,6 +1,6 @@
/**
* GitHub REST plumbing shared by the issue reconcilers (close-solved,
* close-topics).
* GitHub REST + GraphQL plumbing shared by the issue reconcilers (close-solved,
* close-topics) and the Project field reconciler (sync-project-fields).
*
* Importing this module is side-effect free — nothing resolves credentials or
* touches the network until github() is awaited — so a script can import it
@@ -22,6 +22,8 @@ export interface GitHub {
repo: string;
/** One authenticated request against api.github.com; throws on non-2xx. */
api(path: string, init?: RequestInit): Promise<unknown>;
/** One GraphQL call (Projects v2 lives here); throws on transport or query errors. */
graphql(query: string, variables?: Record<string, unknown>): Promise<unknown>;
/** Every page of a list endpoint, flattened into one stream of elements. */
list(path: string): AsyncGenerator<unknown, void, void>;
/** Comment on an issue, then close it as completed. */
@@ -74,6 +76,24 @@ export async function github(): Promise<GitHub> {
}
}
async function graphql(
query: string,
variables: Record<string, unknown> = {},
): Promise<unknown> {
const res = await fetch("https://api.github.com/graphql", {
method: "POST",
headers: {
authorization: `Bearer ${token}`,
"content-type": "application/json",
},
body: JSON.stringify({ query, variables }),
});
if (!res.ok) throw new Error(`graphql -> ${res.status} ${await res.text()}`);
const payload = (await res.json()) as { data?: unknown; errors?: { message: string }[] };
if (payload.errors?.length) throw new Error(payload.errors.map((e) => e.message).join("; "));
return payload.data;
}
/**
* Comment before closing: if the PATCH fails, the issue still carries a
* visible note of what the automation decided, instead of failing silently.
@@ -89,5 +109,5 @@ export async function github(): Promise<GitHub> {
});
}
return { repo, api, list, closeIssue };
return { repo, api, graphql, list, closeIssue };
}