Skip to content

Commit fa8fdb9

Browse files
feat: add createOrUpdatePullRequest function with tests for PR creation and updates
1 parent 864a528 commit fa8fdb9

File tree

6 files changed

+371
-1
lines changed

6 files changed

+371
-1
lines changed

docs/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Use Context7 MCP for up to date documentation.
149149
Create `chore/bump-python-<track>`. Commit updated files.
150150
Verify: Local e2e shows new branch and commit.
151151

152-
19. [ ] **Create PR via Octokit**
152+
19. [x] **Create PR via Octokit**
153153
Title, body with changelog links, manifest evidence, diff summary, rollback. Labels.
154154
Verify: Sandbox repo e2e PR opens with exact content.
155155

package-lock.json

Lines changed: 183 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"homepage": "https://github.com/CasperKristiansson/python-version-patch-pr#readme",
4040
"dependencies": {
4141
"@actions/core": "^1.10.1",
42+
"@octokit/rest": "^22.0.0",
4243
"cheerio": "^1.1.2",
4344
"fast-glob": "^3.3.3",
4445
"semver": "^7.7.3",

src/git/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
export { createBranchAndCommit } from './branch';
22
export type { BranchCommitOptions, BranchCommitResult } from './branch';
3+
4+
export { createOrUpdatePullRequest } from './pull-request';
5+
export type { PullRequestOptions, PullRequestResult, OctokitClient } from './pull-request';

src/git/pull-request.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { Octokit } from '@octokit/rest';
2+
3+
export interface OctokitClient {
4+
pulls: {
5+
list: (params: {
6+
owner: string;
7+
repo: string;
8+
head: string;
9+
state: 'open';
10+
per_page?: number;
11+
}) => Promise<{ data: Array<{ number: number; html_url?: string }> }>;
12+
create: (params: {
13+
owner: string;
14+
repo: string;
15+
head: string;
16+
base: string;
17+
title: string;
18+
body: string;
19+
draft?: boolean;
20+
maintainer_can_modify?: boolean;
21+
}) => Promise<{ data: { number: number; html_url?: string } }>;
22+
update: (params: {
23+
owner: string;
24+
repo: string;
25+
pull_number: number;
26+
title: string;
27+
body: string;
28+
maintainer_can_modify?: boolean;
29+
}) => Promise<{ data: { number: number; html_url?: string } }>;
30+
};
31+
}
32+
33+
export interface PullRequestOptions {
34+
owner: string;
35+
repo: string;
36+
head: string;
37+
base: string;
38+
title: string;
39+
body: string;
40+
authToken: string;
41+
draft?: boolean;
42+
maintainerCanModify?: boolean;
43+
client?: OctokitClient;
44+
}
45+
46+
export interface PullRequestResult {
47+
action: 'created' | 'updated';
48+
number: number;
49+
url: string | undefined;
50+
}
51+
52+
const USER_AGENT = 'python-version-patch-pr/0.1.0';
53+
54+
function createClient(authToken: string): OctokitClient {
55+
return new Octokit({ auth: authToken, userAgent: USER_AGENT });
56+
}
57+
58+
export async function createOrUpdatePullRequest(
59+
options: PullRequestOptions,
60+
): Promise<PullRequestResult> {
61+
const { owner, repo, head, base, title, body, authToken, draft, maintainerCanModify, client } =
62+
options;
63+
64+
const octokit = client ?? createClient(authToken);
65+
66+
const { data: existing } = await octokit.pulls.list({
67+
owner,
68+
repo,
69+
head: `${owner}:${head}`,
70+
state: 'open',
71+
per_page: 1,
72+
});
73+
74+
if (existing.length > 0) {
75+
const pull = existing[0];
76+
const response = await octokit.pulls.update({
77+
owner,
78+
repo,
79+
pull_number: pull.number,
80+
title,
81+
body,
82+
maintainer_can_modify: maintainerCanModify,
83+
});
84+
85+
return { action: 'updated', number: response.data.number, url: response.data.html_url };
86+
}
87+
88+
const response = await octokit.pulls.create({
89+
owner,
90+
repo,
91+
head,
92+
base,
93+
title,
94+
body,
95+
draft,
96+
maintainer_can_modify: maintainerCanModify,
97+
});
98+
99+
return { action: 'created', number: response.data.number, url: response.data.html_url };
100+
}

0 commit comments

Comments
 (0)