1 | async function valueToTreeObject(octokit, owner, repo, path, value) {
|
2 |
|
3 | if (typeof value === "string") {
|
4 | return {
|
5 | path,
|
6 | mode: "100644",
|
7 | content: value,
|
8 | };
|
9 | }
|
10 |
|
11 |
|
12 | const { data } = await octokit.request("POST /repos/{owner}/{repo}/git/blobs", {
|
13 | owner,
|
14 | repo,
|
15 | ...value,
|
16 | });
|
17 | const blobSha = data.sha;
|
18 | return {
|
19 | path,
|
20 | mode: "100644",
|
21 | sha: blobSha,
|
22 | };
|
23 | }
|
24 |
|
25 | async function createTree(state, changes) {
|
26 | const { octokit, owner, repo, fork, latestCommitSha, latestCommitTreeSha, } = state;
|
27 | const tree = (await Promise.all(Object.keys(changes.files).map(async (path) => {
|
28 | const value = changes.files[path];
|
29 | if (value === null) {
|
30 |
|
31 |
|
32 | try {
|
33 |
|
34 | await octokit.request("HEAD /repos/{owner}/{repo}/contents/:path", {
|
35 | owner: fork,
|
36 | repo,
|
37 | ref: latestCommitSha,
|
38 | path,
|
39 | });
|
40 | return {
|
41 | path,
|
42 | mode: "100644",
|
43 | sha: null,
|
44 | };
|
45 | }
|
46 | catch (error) {
|
47 | return;
|
48 | }
|
49 | }
|
50 |
|
51 |
|
52 | if (typeof value === "function") {
|
53 | let result;
|
54 | try {
|
55 | const { data: file } = await octokit.request("GET /repos/{owner}/{repo}/contents/:path", {
|
56 | owner: fork,
|
57 | repo,
|
58 | ref: latestCommitSha,
|
59 | path,
|
60 | });
|
61 | result = await value(Object.assign(file, { exists: true }));
|
62 | }
|
63 | catch (error) {
|
64 |
|
65 | if (error.status !== 404)
|
66 | throw error;
|
67 |
|
68 | result = await value({ exists: false });
|
69 | }
|
70 | if (result === null || typeof result === "undefined")
|
71 | return;
|
72 | return valueToTreeObject(octokit, owner, repo, path, result);
|
73 | }
|
74 | return valueToTreeObject(octokit, owner, repo, path, value);
|
75 | }))).filter(Boolean);
|
76 | if (tree.length === 0) {
|
77 | return null;
|
78 | }
|
79 |
|
80 | const { data: { sha: newTreeSha }, } = await octokit.request("POST /repos/{owner}/{repo}/git/trees", {
|
81 | owner: fork,
|
82 | repo,
|
83 | base_tree: latestCommitTreeSha,
|
84 | tree,
|
85 | });
|
86 | return newTreeSha;
|
87 | }
|
88 |
|
89 | async function createCommit(state, treeCreated, changes) {
|
90 | const { octokit, repo, fork, latestCommitSha } = state;
|
91 | const message = treeCreated
|
92 | ? changes.commit
|
93 | : typeof changes.emptyCommit === "string"
|
94 | ? changes.emptyCommit
|
95 | : changes.commit;
|
96 |
|
97 | const { data: latestCommit } = await octokit.request("POST /repos/{owner}/{repo}/git/commits", {
|
98 | owner: fork,
|
99 | repo,
|
100 | message,
|
101 | tree: state.latestCommitTreeSha,
|
102 | parents: [latestCommitSha],
|
103 | });
|
104 | return latestCommit.sha;
|
105 | }
|
106 |
|
107 | async function composeCreatePullRequest(octokit, { owner, repo, title, body, base, head, createWhenEmpty, changes: changesOption, draft = false, }) {
|
108 | const changes = Array.isArray(changesOption)
|
109 | ? changesOption
|
110 | : [changesOption];
|
111 | if (changes.length === 0)
|
112 | throw new Error('[octokit-plugin-create-pull-request] "changes" cannot be an empty array');
|
113 | const state = { octokit, owner, repo };
|
114 |
|
115 | const { data: repository, headers } = await octokit.request("GET /repos/{owner}/{repo}", {
|
116 | owner,
|
117 | repo,
|
118 | });
|
119 | const isUser = !!headers["x-oauth-scopes"];
|
120 | if (!repository.permissions) {
|
121 | throw new Error("[octokit-plugin-create-pull-request] Missing authentication");
|
122 | }
|
123 | if (!base) {
|
124 | base = repository.default_branch;
|
125 | }
|
126 | state.fork = owner;
|
127 | if (isUser && !repository.permissions.push) {
|
128 |
|
129 | const user = await octokit.request("GET /user");
|
130 |
|
131 | const forks = await octokit.request("GET /repos/{owner}/{repo}/forks", {
|
132 | owner,
|
133 | repo,
|
134 | });
|
135 | const hasFork = forks.data.find(
|
136 |
|
137 | (fork) => fork.owner?.login === user.data.login);
|
138 | if (!hasFork) {
|
139 |
|
140 | await octokit.request("POST /repos/{owner}/{repo}/forks", {
|
141 | owner,
|
142 | repo,
|
143 | });
|
144 | }
|
145 | state.fork = user.data.login;
|
146 | }
|
147 |
|
148 | const { data: [latestCommit], } = await octokit.request("GET /repos/{owner}/{repo}/commits", {
|
149 | owner,
|
150 | repo,
|
151 | sha: base,
|
152 | per_page: 1,
|
153 | });
|
154 | state.latestCommitSha = latestCommit.sha;
|
155 | state.latestCommitTreeSha = latestCommit.commit.tree.sha;
|
156 | const baseCommitTreeSha = latestCommit.commit.tree.sha;
|
157 | for (const change of changes) {
|
158 | let treeCreated = false;
|
159 | if (change.files && Object.keys(change.files).length) {
|
160 | const latestCommitTreeSha = await createTree(state, change);
|
161 | if (latestCommitTreeSha) {
|
162 | state.latestCommitTreeSha = latestCommitTreeSha;
|
163 | treeCreated = true;
|
164 | }
|
165 | }
|
166 | if (treeCreated || change.emptyCommit !== false) {
|
167 | state.latestCommitSha = await createCommit(state, treeCreated, change);
|
168 | }
|
169 | }
|
170 | const hasNoChanges = baseCommitTreeSha === state.latestCommitTreeSha;
|
171 | if (hasNoChanges && createWhenEmpty === false) {
|
172 | return null;
|
173 | }
|
174 |
|
175 | await octokit.request("POST /repos/{owner}/{repo}/git/refs", {
|
176 | owner: state.fork,
|
177 | repo,
|
178 | sha: state.latestCommitSha,
|
179 | ref: `refs/heads/${head}`,
|
180 | });
|
181 |
|
182 | return await octokit.request("POST /repos/{owner}/{repo}/pulls", {
|
183 | owner,
|
184 | repo,
|
185 | head: `${state.fork}:${head}`,
|
186 | base,
|
187 | title,
|
188 | body,
|
189 | draft,
|
190 | });
|
191 | }
|
192 |
|
193 | const VERSION = "3.9.2";
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | function createPullRequest(octokit) {
|
199 | return {
|
200 | createPullRequest: composeCreatePullRequest.bind(null, octokit),
|
201 | };
|
202 | }
|
203 | createPullRequest.VERSION = VERSION;
|
204 |
|
205 | export { composeCreatePullRequest, createPullRequest };
|
206 |
|