-
Notifications
You must be signed in to change notification settings - Fork 377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(github): get files from commits w/out PRs #825
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import {createPullRequest, Changes} from 'code-suggester'; | |
import {Octokit} from '@octokit/rest'; | ||
import {request} from '@octokit/request'; | ||
import {graphql} from '@octokit/graphql'; | ||
import {Endpoints} from '@octokit/types'; | ||
// The return types for responses have not yet been exposed in the | ||
// @octokit/* libraries, we explicitly define the types below to work | ||
// around this,. See: https://github.com/octokit/rest.js/issues/1624 | ||
|
@@ -45,6 +46,8 @@ type CreateIssueCommentResponse = PromiseValue< | |
// see: PromiseValue< | ||
// ReturnType<InstanceType<typeof Octokit>['repos']['createRelease']> | ||
// >['data']; | ||
type CommitsListResponse = Endpoints['GET /repos/{owner}/{repo}/commits']['response']; | ||
type CommitGetResponse = Endpoints['GET /repos/{owner}/{repo}/commits/{ref}']['response']; | ||
export type ReleaseCreateResponse = { | ||
name: string; | ||
tag_name: string; | ||
|
@@ -281,6 +284,84 @@ export class GitHub { | |
} | ||
} | ||
|
||
async commitsSinceShaRest( | ||
sha?: string, | ||
path?: string, | ||
per_page = 100 | ||
): Promise<Commit[]> { | ||
let page = 1; | ||
let found = false; | ||
const baseBranch = await this.getDefaultBranch(); | ||
const commits = []; | ||
while (!found) { | ||
const response = await this.request( | ||
'GET /repos/{owner}/{repo}/commits{?sha,page,per_page,path}', | ||
{ | ||
owner: this.owner, | ||
repo: this.repo, | ||
sha: baseBranch, | ||
page, | ||
per_page, | ||
path, | ||
} | ||
); | ||
for (const commit of (response as CommitsListResponse).data) { | ||
if (commit.sha === sha) { | ||
found = true; | ||
break; | ||
} | ||
// skip merge commits | ||
if (commit.parents.length === 2) { | ||
continue; | ||
} | ||
commits.push([commit.sha, commit.commit.message]); | ||
} | ||
page++; | ||
} | ||
const ret = []; | ||
for (const [ref, message] of commits) { | ||
const files = []; | ||
let page = 1; | ||
let moreFiles = true; | ||
while (moreFiles) { | ||
// the "Get Commit" resource is a bit of an outlier in terms of GitHub's | ||
// normal pagination: https://git.io/JmVZq | ||
// The behavior is to return an object representing the commit, a | ||
// property of which is an array of files. GitHub will return as many | ||
// associated files as there are, up to a limit of 300, on the initial | ||
// request. If there are more associated files, it will send "Links" | ||
// headers to get the next set. There is a total limit of 3000 | ||
// files returned per commit. | ||
// In practice, the links headers are just the same resourceID plus a | ||
// "page=N" query parameter with "page=1" being the initial set. | ||
// | ||
// TODO: it is more robust to follow the link.next headers (in case | ||
// GitHub ever changes the pattern) OR use ocktokit pagination for this | ||
// endpoint when https://git.io/JmVll is addressed. | ||
const response = (await this.request( | ||
'GET /repos/{owner}/{repo}/commits/{ref}{?page}', | ||
{owner: this.owner, repo: this.repo, ref, page} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see code comment in feedback |
||
)) as CommitGetResponse; | ||
const commitFiles = response.data.files; | ||
if (!commitFiles) { | ||
moreFiles = false; | ||
break; | ||
} | ||
files.push(...commitFiles.map(f => f.filename ?? '')); | ||
// < 300 files means we hit the end | ||
// page === 10 means we're at 3000 and that's the limit GH is gonna | ||
// cough up anyway. | ||
if (commitFiles.length < 300 || page === 10) { | ||
moreFiles = false; | ||
break; | ||
} | ||
page++; | ||
} | ||
ret.push({sha: ref, message, files}); | ||
} | ||
return ret; | ||
} | ||
|
||
// Commit.files only for commits from PRs. | ||
async commitsSinceSha( | ||
sha: string | undefined, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -504,7 +504,7 @@ export class Manifest { | |
if (fromSha === undefined) { | ||
fromSha = (await this.getConfigJson())['bootstrap-sha']; | ||
} | ||
return this.gh.commitsSinceSha(fromSha); | ||
return this.gh.commitsSinceShaRest(fromSha); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any food reason for us to keep Perhaps just open a tracking ticket to get rid of it? (I understand not wanting to do it as part of this work). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. created #830 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you 👏 |
||
} | ||
|
||
async pullRequest(): Promise<number | undefined> { | ||
|
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 know this is kind of hacky/rookie... but do you mind if I just add a tracking issue to harden/future-proof it (maybe add to #830)?