xref: /expo/tools/src/GitHub.ts (revision f8111c10)
1import { Octokit, RestEndpointMethodTypes } from '@octokit/rest';
2
3const octokit = new Octokit({
4  auth: process.env.GITHUB_TOKEN,
5});
6
7// Predefine some params used across almost all requests.
8const owner = 'expo';
9const repo = 'expo';
10
11/**
12 * Returns public informations about the currently authenticated (by GitHub API token) user.
13 */
14export async function getAuthenticatedUserAsync() {
15  const { data } = await octokit.users.getAuthenticated();
16  return data;
17}
18
19/**
20 * Requests for the pull request object.
21 */
22export async function getPullRequestAsync(pull_number: number): Promise<PullRequest> {
23  const { data } = await octokit.pulls.get({
24    owner,
25    repo,
26    pull_number,
27  });
28  return data;
29}
30
31/**
32 * Gets a list of reviews left in the pull request with given ID.
33 */
34export async function listPullRequestReviewsAsync(
35  pull_number: number
36): Promise<PullRequestReview[]> {
37  const { data } = await octokit.pulls.listReviews({
38    owner,
39    repo,
40    pull_number,
41  });
42  return data;
43}
44
45/**
46 * Creates pull request review. By default the review is pending which needs to be submitted in order to be visible for other users.
47 * Provide `event` option to create and submit at once.
48 */
49export async function createPullRequestReviewAsync<T>(
50  pull_number: number,
51  options?: T
52): Promise<PullRequestReview> {
53  const { data } = await octokit.pulls.createReview({
54    owner,
55    repo,
56    pull_number,
57    ...options,
58  });
59  return data;
60}
61
62/**
63 * Updates pull request review with a new main comment.
64 */
65export async function updatePullRequestReviewAsync(
66  pull_number: number,
67  review_id: number,
68  body: string
69) {
70  const { data } = await octokit.pulls.updateReview({
71    owner,
72    repo,
73    pull_number,
74    review_id,
75    body,
76  });
77  return data;
78}
79
80/**
81 * Gets a list of comments in review.
82 */
83export async function listPullRequestReviewCommentsAsync(pull_number: number, review_id: number) {
84  const { data } = await octokit.pulls.listReviewComments({
85    owner,
86    repo,
87    pull_number,
88    review_id,
89  });
90  return data;
91}
92
93/**
94 * Deletes a comment left under pull request review.
95 */
96export async function deletePullRequestReviewCommentAsync(comment_id: number) {
97  const { data } = await octokit.pulls.deleteReviewComment({
98    owner,
99    repo,
100    comment_id,
101  });
102  return data;
103}
104
105/**
106 * Deletes all comments from given review.
107 */
108export async function deleteAllPullRequestReviewCommentsAsync(
109  pull_number: number,
110  review_id: number
111) {
112  const comments = await listPullRequestReviewCommentsAsync(pull_number, review_id);
113
114  await Promise.all(
115    comments
116      .filter((comment) => comment.pull_request_review_id === review_id)
117      .map((comment) => deletePullRequestReviewCommentAsync(comment.id))
118  );
119}
120
121/**
122 * Requests given users to review the pull request.
123 * If the user already reviewed the PR, it resets his review state.
124 */
125export async function requestPullRequestReviewersAsync(pull_number: number, reviewers: string[]) {
126  const { data } = await octokit.pulls.requestReviewers({
127    owner,
128    repo,
129    pull_number,
130    reviewers,
131  });
132  return data;
133}
134
135/**
136 * Adds labels to the issue. Throws an error when any of given labels doesn't exist.
137 */
138export async function addIssueLabelsAsync(issue_number: number, labels: string[]) {
139  const { data } = await octokit.issues.addLabels({
140    owner,
141    repo,
142    issue_number,
143    labels,
144  });
145  return data;
146}
147
148/**
149 * Removes single label from the issue.
150 * Throws an error when given label doesn't exist and when the label isn't added.
151 */
152export async function removeIssueLabelAsync(issue_number: number, name: string) {
153  const { data } = await octokit.issues.removeLabel({
154    owner,
155    repo,
156    issue_number,
157    name,
158  });
159  return data;
160}
161
162// Octokit's types are autogenerated and so inconvenient to use if you want to refer to them.
163// We re-export some of them to make it easier.
164export type PullRequestReviewEvent = 'COMMENT' | 'APPROVE' | 'REQUEST_CHANGES';
165export type PullRequest = RestEndpointMethodTypes['pulls']['get']['response']['data'];
166export type PullRequestReview = RestEndpointMethodTypes['pulls']['getReview']['response']['data'];
167