Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 23 additions & 14 deletions pstack/skills/poteto-mode/scripts/watch-pr/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,20 +489,29 @@ export class GhGitHubReader implements T.GitHubReader {
async openPullRequests(
repository: T.Repository
): Promise<readonly T.OpenPullRequest[]> {
const value = await runJson([
"gh",
"pr",
"list",
"--repo",
`${repository.owner}/${repository.repo}`,
"--state",
"open",
"--limit",
"300",
"--json",
"number,headRefName,baseRefName,isCrossRepository",
]);
return list(value, "open PRs").map((item, index) => {
// gh lists the newest PRs first and stops at --limit, so a full page may
// have cut off an older stack parent. Ask again until the list is short.
let value: readonly unknown[];
for (let limit = 300; ; limit *= 2) {
value = list(
await runJson([
"gh",
"pr",
"list",
"--repo",
`${repository.owner}/${repository.repo}`,
"--state",
"open",
"--limit",
String(limit),
"--json",
"number,headRefName,baseRefName,isCrossRepository",
]),
"open PRs"
);
if (value.length < limit) break;
}
return value.map((item, index) => {
const object = record(item, `open PRs[${index}]`);
if (typeof object.isCrossRepository !== "boolean")
missing(`open PRs[${index}].isCrossRepository`, object.isCrossRepository);
Expand Down
41 changes: 41 additions & 0 deletions pstack/skills/poteto-mode/scripts/watch-pr/open-pulls.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, expect, it } from "bun:test";
import { spawnSync } from "node:child_process";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";

describe("open pull request discovery", () => {
it("keeps a stack parent that is older than the first 300 open PRs", () => {
const directory = mkdtempSync(join(tmpdir(), "watch-pr-open-pulls-"));
try {
// Like gh, the fake returns the newest open PRs first and stops at --limit.
writeFileSync(
join(directory, "gh"),
`#!${process.execPath}
const args = process.argv.slice(2);
const limit = Number(args[args.indexOf("--limit") + 1]);
const rows = [];
for (let number = 400; number > 1; number -= 1)
rows.push({ number, headRefName: "other-" + number, baseRefName: "main", isCrossRepository: false });
rows[0] = { number: 400, headRefName: "feature", baseRefName: "base-feature", isCrossRepository: false };
rows.push({ number: 1, headRefName: "base-feature", baseRefName: "main", isCrossRepository: false });
console.log(JSON.stringify(rows.slice(0, limit)));
`,
{ mode: 0o755 }
);
const program = `import { GhGitHubReader, discoverStack } from ${JSON.stringify(import.meta.dir + "/github.ts")};
const stack = await discoverStack(new GhGitHubReader(), { owner: "owner", repo: "repo", number: 400 });
console.log(JSON.stringify(stack.map((item) => item.number)));`;
const child = spawnSync(process.execPath, ["-e", program], {
encoding: "utf8",
timeout: 5000,
env: { ...process.env, PATH: directory + ":" + process.env.PATH },
});
expect(child.error).toBeUndefined();
expect(child.status).toBe(0);
expect(JSON.parse(child.stdout)).toEqual([1, 400]);
} finally {
rmSync(directory, { recursive: true, force: true });
}
});
});
Loading