1 | |
2 |
|
3 | |
4 | * Commit files |
5 | * Create or update one or more files on a branch in a single commit. Each file is created when it doesn't exist on the branch and updated otherwise. When the branch doesn't exist, set start_branch to create it from that branch. |
6 | */ |
7 | export async function main( |
8 | auth: RT.Gitlab, |
9 | project: string, |
10 | branch: string, |
11 | commit_message: string, |
12 | files: { file_path: string; content: string; encoding?: "text" | "base64" }[], |
13 | start_branch: string | undefined, |
14 | author_name: string | undefined, |
15 | author_email: string | undefined |
16 | ) { |
17 | const api = `${(auth.baseUrl || "https://gitlab.com").replace(/\/+$/, "")}/api/v4/projects/${encodeURIComponent(project)}/repository` |
18 | const paths = files.map((f) => f?.file_path) |
19 | const repeated = paths.find((path, i) => paths.indexOf(path) !== i) |
20 | if (!files.length || paths.some((path) => !path) || repeated) { |
21 | throw new Error( |
22 | repeated |
23 | ? `${repeated} is listed twice in files` |
24 | : "Every file needs a file_path" |
25 | ) |
26 | } |
27 | const headers = { |
28 | Authorization: `Bearer ${auth.token}`, |
29 | Accept: "application/json", |
30 | } |
31 | |
32 | const branchResponse = await fetch( |
33 | `${api}/branches/${encodeURIComponent(branch)}`, |
34 | { headers } |
35 | ) |
36 | const branchText = await branchResponse.text() |
37 | const branchExists = branchResponse.ok |
38 | if (!branchExists && !branchText.includes("Branch Not Found")) { |
39 | throw new Error(`${branchResponse.status} ${branchText}`) |
40 | } |
41 | if (!branchExists && !start_branch) { |
42 | throw new Error( |
43 | `Branch ${branch} does not exist: set start_branch to create it` |
44 | ) |
45 | } |
46 | |
47 | const ref = branchExists ? branch : start_branch! |
48 | |
49 | const actions = [] |
50 | for (let i = 0; i < files.length; i += 10) { |
51 | actions.push( |
52 | ...(await Promise.all( |
53 | files.slice(i, i + 10).map(async (f) => { |
54 | const head = await fetch( |
55 | `${api}/files/${encodeURIComponent(f.file_path)}?ref=${encodeURIComponent(ref)}`, |
56 | { method: "HEAD", headers } |
57 | ) |
58 | if (!head.ok && head.status !== 404) { |
59 | throw new Error(`${head.status} checking ${f.file_path} on ${ref}`) |
60 | } |
61 | return { |
62 | action: head.ok ? "update" : "create", |
63 | file_path: f.file_path, |
64 | content: f.content, |
65 | encoding: f.encoding || "text", |
66 | } |
67 | }) |
68 | )) |
69 | ) |
70 | } |
71 |
|
72 | const response = await fetch(`${api}/commits`, { |
73 | method: "POST", |
74 | headers: { ...headers, "Content-Type": "application/json" }, |
75 | body: JSON.stringify({ |
76 | branch, |
77 | start_branch: branchExists ? undefined : start_branch, |
78 | commit_message, |
79 | actions, |
80 | author_name: author_name || undefined, |
81 | author_email: author_email || undefined, |
82 | }), |
83 | }) |
84 |
|
85 | if (!response.ok) { |
86 | throw new Error(`${response.status} ${await response.text()}`) |
87 | } |
88 |
|
89 | return await response.json() |
90 | } |
91 |
|