-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathapi.ts
138 lines (128 loc) · 3.44 KB
/
api.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
137
138
import { FetchError, ofetch } from "ofetch";
import type {
Commit,
Comparison,
DiffEntry,
EncodedFile,
PullRequest,
User,
} from "./types";
import { githubPatStorage } from "../storage";
import { logger } from "../logger";
export function createGithubApi() {
/**
* Fetch with some default headers and authentication.
*/
const fetch = ofetch.create({
baseURL: "https://api.github.com",
headers: {
"X-GitHub-Api-Version": "2022-11-28",
Accept: "application/vnd.github+json",
},
async onRequest(ctx) {
if (!ctx.options.headers.has("Authorization")) {
const token = await githubPatStorage.getValue();
ctx.options.headers.set("Authorization", `Bearer ${token}`);
}
},
});
return {
/**
* Throws an error if the PAT is not valid
*/
async getUser(token: string): Promise<User> {
return await fetch<User>("/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
},
/**
* Returns the repo's git attributes, or undefined if the file does not exist
*/
async getGitAttributesFile(options: {
owner: string;
repo: string;
ref: string;
}): Promise<string | undefined> {
try {
const encodedFile = await fetch<EncodedFile>(
`/repos/${options.owner}/${options.repo}/contents/.gitattributes`,
{
query: {
ref: options.ref,
},
},
);
logger.debug(encodedFile);
return atob(encodedFile.content);
} catch (err) {
if (err instanceof FetchError && err.statusCode === 404) {
return undefined;
} else {
throw err;
}
}
},
/**
* Load information about a PR.
*/
async getPr(options: {
owner: string;
repo: string;
pr: number;
}): Promise<PullRequest> {
return await fetch<PullRequest>(
`/repos/${options.owner}/${options.repo}/pulls/${options.pr}`,
);
},
/**
* Load information about a commit.
*/
async getCommit(options: {
owner: string;
repo: string;
ref: string;
}): Promise<Commit> {
return await fetch<Commit>(
`/repos/${options.owner}/${options.repo}/commits/${options.ref}`,
);
},
/**
* Load all files in a PR.
*/
async getAllPrFiles(options: {
owner: string;
repo: string;
pr: number;
}): Promise<DiffEntry[]> {
const results: DiffEntry[] = [];
let pageResults: DiffEntry[] = [];
let page = 1;
const perPage = 100;
do {
logger.debug("Fetching PR page:", page);
// TODO: reuse getPr with page and per_page query params
pageResults = await fetch<DiffEntry[]>(
`/repos/${options.owner}/${options.repo}/pulls/${options.pr}/files?page=${page}&per_page=${perPage}`,
);
results.push(...pageResults);
page++;
} while (pageResults.length === perPage);
return results;
},
/**
* Get info about the comparison between two commits.
*/
async compareCommits(options: {
owner: string;
repo: string;
commitRefs: [string, string];
}): Promise<Comparison> {
return await fetch<Comparison>(
`/repos/${options.owner}/${options.repo}/compare/${options.commitRefs[0]}...${options.commitRefs[1]}`,
);
},
};
}
export type GithubApi = ReturnType<typeof createGithubApi>;