This repository has been archived by the owner on Jun 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Abstracted code logic #108
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
31d3020
abstracted config fetching
Bullrich ad4623e
moved logic to its own class
Bullrich 0eab4ea
added diff & getFiles to abstraction
Bullrich c15f5a4
moved fetch reviews to api class
Bullrich 59f13b0
abstracted pr modification code
Bullrich 50c8090
feat: added continuous testing
Bullrich 0584078
added comments to the methods
Bullrich 0fe2729
abstracted the combine users octokit access
Bullrich 7e7ca73
removed unused code
Bullrich 307e352
replaced runChecks method for new wrapper
Bullrich 19d48f1
removed duplicated CI
Bullrich File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { GitHub } from "@actions/github/lib/utils"; | ||
import { OctokitResponse } from "@octokit/types"; | ||
import YAML from "yaml"; | ||
|
||
import { | ||
configFilePath, | ||
maxGithubApiFilesPerPage, | ||
maxGithubApiReviewsPerPage, | ||
maxGithubApiTeamMembersPerPage, | ||
} from "src/constants"; | ||
import { Configuration, Context, PR } from "src/types"; | ||
import { configurationSchema } from "src/validation"; | ||
|
||
import { ActionLoggerInterface } from "./action/logger"; | ||
|
||
export interface Review { | ||
state: "COMMENTED" | "REQUEST_CHANGES" | "APPROVE" | string; | ||
user?: { id: number; login: string } | null; | ||
id: number; | ||
} | ||
|
||
/** Class in charge of interacting with GitHub. */ | ||
export class GitHubApi { | ||
private readonly octokit: InstanceType<typeof GitHub>; | ||
private readonly logger: ActionLoggerInterface; | ||
|
||
constructor(private readonly pr: PR, { octokit, logger }: Context) { | ||
this.octokit = octokit; | ||
this.logger = logger; | ||
} | ||
|
||
/** Fetches the config file and validates that is the correct type/format */ | ||
async fetchConfigFile(): Promise<Configuration | null> { | ||
const configFileResponse = await this.octokit.rest.repos.getContent({ | ||
owner: this.pr.base.repo.owner.login, | ||
repo: this.pr.base.repo.name, | ||
path: configFilePath, | ||
}); | ||
if (!("content" in configFileResponse.data)) { | ||
this.logger.fatal(`Did not find "content" key in the response for ${configFilePath}`); | ||
this.logger.info(configFileResponse.data); | ||
return null; | ||
} | ||
|
||
const { content: configFileContentsEnconded } = configFileResponse.data; | ||
if (typeof configFileContentsEnconded !== "string") { | ||
this.logger.fatal(`Content response for ${configFilePath} had unexpected type (expected string)`); | ||
this.logger.info(configFileResponse.data); | ||
return null; | ||
} | ||
|
||
const configFileContents = Buffer.from(configFileContentsEnconded, "base64").toString("utf-8"); | ||
|
||
const configValidationResult = configurationSchema.validate(YAML.parse(configFileContents)); | ||
if (configValidationResult.error) { | ||
this.logger.fatal("Configuration file is invalid"); | ||
this.logger.info(configValidationResult.error); | ||
return null; | ||
} | ||
|
||
return configValidationResult.value; | ||
} | ||
|
||
/** Fetches the diff in the PR */ | ||
async fetchDiff(): Promise<string> { | ||
const diffResponse = (await this.octokit.rest.pulls.get({ | ||
owner: this.pr.base.repo.owner.login, | ||
repo: this.pr.base.repo.name, | ||
pull_number: this.pr.number, | ||
mediaType: { format: "diff" }, | ||
})) /* Octokit doesn't inform the right return type for mediaType: { format: "diff" } */ as unknown as OctokitResponse<string>; | ||
return diffResponse.data; | ||
} | ||
|
||
/** Returns a list of all files that were changed */ | ||
async fetchChangedFiles(): Promise<string[]> { | ||
const data = await this.octokit.paginate("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", { | ||
owner: this.pr.base.repo.owner.login, | ||
repo: this.pr.base.repo.name, | ||
pull_number: this.pr.number, | ||
per_page: maxGithubApiFilesPerPage, | ||
}); | ||
return data.map(({ filename }) => filename); | ||
} | ||
|
||
/** Fetches the list of reviews to a repo | ||
* Includes comments and failed reviews | ||
*/ | ||
async fetchReviews(): Promise<Review[]> { | ||
return await this.octokit.paginate("GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews", { | ||
owner: this.pr.base.repo.owner.login, | ||
repo: this.pr.base.repo.name, | ||
pull_number: this.pr.number, | ||
per_page: maxGithubApiReviewsPerPage, | ||
}); | ||
} | ||
|
||
/** Request users/teams to review this PR */ | ||
async requestReviewers(users: string[], teams: string[]): Promise<void> { | ||
await this.octokit.request("POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers", { | ||
owner: this.pr.base.repo.owner.login, | ||
repo: this.pr.base.repo.name, | ||
pull_number: this.pr.number, | ||
reviewers: users, | ||
team_reviewers: teams, | ||
}); | ||
} | ||
|
||
/** Gets all the members belonging to a team */ | ||
async getTeamMembers(team_slug: string): Promise<string[]> { | ||
return await this.octokit.paginate( | ||
this.octokit.rest.teams.listMembersInOrg, | ||
{ org: this.pr.base.repo.owner.login, team_slug, per_page: maxGithubApiTeamMembersPerPage }, | ||
(response) => response.data.map(({ login }) => login), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not taken by
GitHubApi
. Same in other places.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid it's a requirement in the object union that the method is receiving:
I'll look into cleaning it in the future