/
create-tree.ts
136 lines (117 loc) · 3.51 KB
/
create-tree.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { Changes, State, TreeParameter, UpdateFunctionFile } from "./types";
import { valueToTreeObject } from "./value-to-tree-object";
import { DELETE_FILE } from "./constants";
export async function createTree(
state: Required<State>,
changes: Required<Changes>
): Promise<string | null> {
const {
octokit,
owner,
repo,
ownerOrFork,
latestCommitSha,
latestCommitTreeSha,
} = state;
let tree = [];
for (const path of Object.keys(changes.files)) {
const value = changes.files[path];
if (value === DELETE_FILE) {
// Deleting a non-existent file from a tree leads to an "GitRPC::BadObjectState" error,
// so we only attempt to delete the file if it exists.
try {
// https://developer.github.com/v3/repos/contents/#get-contents
await octokit.request("HEAD /repos/{owner}/{repo}/contents/:path", {
owner: ownerOrFork,
repo,
ref: latestCommitSha,
path,
});
tree.push({
path,
mode: "100644",
sha: null,
});
continue;
} catch (error) {
continue;
}
}
// When passed a function, retrieve the content of the file, pass it
// to the function, then return the result
if (typeof value === "function") {
let result;
try {
const { data: file } = await octokit.request(
"GET /repos/{owner}/{repo}/contents/:path",
{
owner: ownerOrFork,
repo,
ref: latestCommitSha,
path,
}
);
result = await value(
Object.assign(file, { exists: true }) as UpdateFunctionFile
);
if (result === DELETE_FILE) {
try {
// https://developer.github.com/v3/repos/contents/#get-contents
await octokit.request("HEAD /repos/{owner}/{repo}/contents/:path", {
owner: ownerOrFork,
repo,
ref: latestCommitSha,
path,
});
tree.push({
path,
mode: "100644",
sha: null,
});
continue;
} catch (error) {
// istanbul ignore next
continue;
}
}
} catch (error) {
// @ts-ignore
// istanbul ignore if
if (error.status !== 404) throw error;
// @ts-ignore
result = await value({ exists: false });
}
if (
result === null ||
typeof result === "undefined" ||
typeof result === "symbol"
) {
continue;
}
tree.push(
// @ts-expect-error - Argument result can never be of type Symbol at this branch
// because the above condition will catch it and move on to the next iteration cycle
await valueToTreeObject(octokit, ownerOrFork, repo, path, result)
);
continue;
}
// @ts-expect-error - Argument value can never be of type Symbol at this branch
// because the above condition will catch it and initiate a file deletion operation
tree.push(await valueToTreeObject(octokit, ownerOrFork, repo, path, value));
continue;
}
tree = tree.filter(Boolean) as TreeParameter;
if (tree.length === 0) {
return null;
}
// https://developer.github.com/v3/git/trees/#create-a-tree
const {
data: { sha: newTreeSha },
} = await octokit.request("POST /repos/{owner}/{repo}/git/trees", {
owner: ownerOrFork,
repo,
base_tree: latestCommitTreeSha,
tree,
});
return newTreeSha;
}