Skip to content

Commit

Permalink
feat(github): add support for only using the REST API (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertCraigie authored Apr 11, 2023
1 parent af30ea6 commit d68bc9d
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 2 deletions.
11 changes: 11 additions & 0 deletions __snapshots__/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Options:
--repo-url GitHub URL to generate release for [required]
--dry-run Prepare but do not take action
[boolean] [default: false]
--use-graphql Whether or not the GraphQL API should be used.
If false, the REST API will be used instead.
[boolean] [default: true]
--include-v-in-tags include "v" in tag versions
[boolean] [default: true]
--monorepo-tags include library name in tags and release
Expand Down Expand Up @@ -91,6 +94,9 @@ Options:
on [string]
--repo-url GitHub URL to generate release for [required]
--dry-run Prepare but do not take action[boolean] [default: false]
--use-graphql Whether or not the GraphQL API should be used. If false,
the REST API will be used instead.
[boolean] [default: true]
--label comma-separated list of labels to add to from release PR
[default: "autorelease: pending"]
--skip-labeling skip application of labels to pull requests
Expand Down Expand Up @@ -132,6 +138,8 @@ Options:
[string]
--repo-url GitHub URL to generate release for [required]
--dry-run Prepare but do not take action [boolean] [default: false]
--use-graphql Whether or not the GraphQL API should be used. If false, the
REST API will be used instead. [boolean] [default: true]
--draft mark release as a draft. no tag is created but tag_name and
target_commitish are associated with the release for future
tag creation upon "un-drafting" the release.
Expand Down Expand Up @@ -179,6 +187,9 @@ Options:
--repo-url GitHub URL to generate release for[required]
--dry-run Prepare but do not take action
[boolean] [default: false]
--use-graphql Whether or not the GraphQL API should be
used. If false, the REST API will be used
instead. [boolean] [default: true]
--release-as override the semantically determined release
version [string]
--bump-minor-pre-major should we bump the semver minor prior to the
Expand Down
8 changes: 8 additions & 0 deletions src/bin/release-please.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface GitHubArgs {
apiUrl?: string;
graphqlUrl?: string;
fork?: boolean;
useGraphql?: boolean;

// deprecated in favor of targetBranch
defaultBranch?: string;
Expand Down Expand Up @@ -183,6 +184,12 @@ function gitHubOptions(yargs: yargs.Argv): yargs.Argv {
type: 'boolean',
default: false,
})
.option('use-graphql', {
describe:
'Whether or not the GraphQL API should be used. If false, the REST API will be used instead.',
type: 'boolean',
default: true,
})
.middleware(_argv => {
const argv = _argv as GitHubArgs;
// allow secrets to be loaded from file path
Expand Down Expand Up @@ -792,6 +799,7 @@ async function buildGitHub(argv: GitHubArgs): Promise<GitHub> {
token: argv.token!,
apiUrl: argv.apiUrl,
graphqlUrl: argv.graphqlUrl,
useGraphql: argv.useGraphql,
});
return github;
}
Expand Down
144 changes: 142 additions & 2 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface GitHubOptions {
repository: Repository;
octokitAPIs: OctokitAPIs;
logger?: Logger;
useGraphql?: boolean;
}

interface ProxyOption {
Expand All @@ -82,6 +83,7 @@ interface GitHubCreateOptions {
token?: string;
logger?: Logger;
proxy?: ProxyOption;
useGraphql?: boolean;
}

type CommitFilter = (commit: Commit) => boolean;
Expand Down Expand Up @@ -208,6 +210,7 @@ export class GitHub {
private graphql: Function;
private fileCache: RepositoryFileCache;
private logger: Logger;
private useGraphql: boolean;

private constructor(options: GitHubOptions) {
this.repository = options.repository;
Expand All @@ -216,6 +219,7 @@ export class GitHub {
this.graphql = options.octokitAPIs.graphql;
this.fileCache = new RepositoryFileCache(this.octokit, this.repository);
this.logger = options.logger ?? defaultLogger;
this.useGraphql = options.useGraphql ?? true;
}

static createDefaultAgent(baseUrl: string, defaultProxy?: ProxyOption) {
Expand Down Expand Up @@ -295,6 +299,7 @@ export class GitHub {
},
octokitAPIs: apis,
logger: options.logger,
useGraphql: options.useGraphql,
};
return new GitHub(opts);
}
Expand Down Expand Up @@ -362,7 +367,18 @@ export class GitHub {
* @yields {Commit}
* @throws {GitHubAPIError} on an API error
*/
async *mergeCommitIterator(
mergeCommitIterator(
targetBranch: string,
options: CommitIteratorOptions = {}
): AsyncGenerator<Commit> {
if (this.useGraphql) {
return this.mergeCommitIteratorGraphql(targetBranch, options);
}

return this.mergeCommitIteratorREST(targetBranch, options);
}

private async *mergeCommitIteratorGraphql(
targetBranch: string,
options: CommitIteratorOptions = {}
) {
Expand Down Expand Up @@ -520,6 +536,84 @@ export class GitHub {
};
}

private async *mergeCommitIteratorREST(
targetBranch: string,
options: CommitIteratorOptions = {}
): AsyncGenerator<Commit> {
const maxResults = options.maxResults ?? Number.MAX_SAFE_INTEGER;
let results = 0;

const iterator = this.octokit.paginate.iterator(
this.octokit.rest.repos.listCommits,
{
owner: this.repository.owner,
repo: this.repository.repo,
per_page: 25,
sha: targetBranch,
}
);

for await (const response of iterator) {
for (let i = 0; i < response.data.length; i++) {
if ((results += 1) > maxResults) {
break;
}

const commitData = response.data[i];
yield await this.mergeCommitREST(
{
sha: commitData.sha,
message: commitData.commit.message,
},
options
);
}
if (results > maxResults) {
break;
}
}
}

private async mergeCommitREST(
commitData: Commit,
options: CommitIteratorOptions
): Promise<Commit> {
const commit = {...commitData};
if (options.backfillFiles) {
commit.files = await this.getCommitFiles(commit.sha);
}

const associatedPRs =
await this.octokit.repos.listPullRequestsAssociatedWithCommit({
owner: this.repository.owner,
repo: this.repository.repo,
commit_sha: commit.sha,
});
if (associatedPRs.data.length) {
const pullRequest = associatedPRs.data.find(
pr => pr.merge_commit_sha === commit.sha
);
if (pullRequest) {
commit.pullRequest = {
sha: commit.sha,
number: pullRequest.number,
baseBranchName: pullRequest.base.ref,
headBranchName: pullRequest.head.ref,
title: pullRequest.title,
body: pullRequest.body ?? '',
labels: pullRequest.labels.map(label => label.name),
files: commit.files ?? [],
};
} else {
this.logger.warn(
`Found ${associatedPRs.data.length} PRs associated with ${commit.sha} but none matched the commit SHA.`
);
}
}

return commit;
}

/**
* Get the list of file paths modified in a given commit.
*
Expand Down Expand Up @@ -808,7 +902,15 @@ export class GitHub {
* @yields {GitHubRelease}
* @throws {GitHubAPIError} on an API error
*/
async *releaseIterator(options: ReleaseIteratorOptions = {}) {
releaseIterator(options: ReleaseIteratorOptions = {}) {
if (this.useGraphql) {
return this.releaseIteratorGraphql(options);
}

return this.releaseIteratorREST(options);
}

private async *releaseIteratorGraphql(options: ReleaseIteratorOptions) {
const maxResults = options.maxResults ?? Number.MAX_SAFE_INTEGER;
let results = 0;
let cursor: string | undefined = undefined;
Expand All @@ -830,6 +932,44 @@ export class GitHub {
}
}

private async *releaseIteratorREST(
options: ReleaseIteratorOptions
): AsyncGenerator<GitHubRelease> {
const maxResults = options.maxResults ?? Number.MAX_SAFE_INTEGER;
let results = 0;

const iterator = this.octokit.paginate.iterator(
this.octokit.rest.repos.listReleases,
{owner: this.repository.owner, repo: this.repository.repo, per_page: 25}
);

for await (const response of iterator) {
for (let i = 0; i < response.data.length; i++) {
if ((results += 1) > maxResults) {
break;
}

const release = response.data[i];
const tag = await this.octokit.git.getRef({
repo: this.repository.repo,
owner: this.repository.owner,
ref: `tags/${release.tag_name}`,
});

yield {
...release,
tagName: release.tag_name,
notes: release.body ?? undefined,
name: release.name ?? undefined,
sha: tag.data.object.sha,
};
}
if (results > maxResults) {
break;
}
}
}

private async releaseGraphQL(
cursor?: string
): Promise<ReleaseHistory | null> {
Expand Down
Loading

0 comments on commit d68bc9d

Please sign in to comment.