UNPKG

@ossjs/release

Version:

Minimalistic, opinionated, and predictable release automation tool.

159 lines (143 loc) 4.16 kB
import { format } from 'outvariant' import { getInfo } from '#/src/utils/git/get-info.js' import type { ParsedCommitWithHash } from '#/src/utils/git/parse-commits.js' import { log } from '#/src/logger.js' export interface GetCommitAuthorsQuery { repository: { pullRequest: { url: string author: { login: string } commits: { nodes: Array<{ commit: { authors: { nodes: Array<{ user: { login: string } }> } } }> } } } } /** * Get a list of GitHub usernames who have contributed * to the given release commit. This analyzes all the commit * authors in the pull request referenced by the given commit. */ export async function getCommitAuthors( commit: ParsedCommitWithHash, ): Promise<Set<string>> { // Extract all GitHub issue references from this commit. const issueRefs: Set<string> = new Set() for (const ref of commit.references) { if (ref.issue) { issueRefs.add(ref.issue) } } if (issueRefs.size === 0) { return new Set() } const repo = await getInfo() const queue: Promise<void>[] = [] const authors: Set<string> = new Set() function addAuthor(login?: string): void { if (!login) { return } authors.add(login) } for (const issueId of issueRefs) { const authorLoginPromise = new Promise<void>(async (resolve, reject) => { const response = await fetch(`https://api.github.com/graphql`, { method: 'POST', headers: { Agent: 'ossjs/release', Accept: 'application/json', Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ query: ` query GetCommitAuthors($owner: String!, $repo: String!, $pullRequestId: Int!) { repository(owner: $owner name: $repo) { pullRequest(number: $pullRequestId) { url author { login } commits(first: 100) { nodes { commit { authors(first: 100) { nodes { user { login } } } } } } } } } `, variables: { owner: repo.owner, repo: repo.name, pullRequestId: Number(issueId), }, }), }) if (!response.ok) { return reject( new Error(format('GitHub API responded with %d.', response.status)), ) } const json = await response.json() const data = json.data as GetCommitAuthorsQuery if (json.errors) { return reject( new Error( format( 'GitHub API responded with %d error(s): %j', json.errors.length, json.errors, ), ), ) } // Add pull request author. addAuthor(data.repository.pullRequest.author.login) // Add each commit author in the pull request. for (const commit of data.repository.pullRequest.commits.nodes) { for (const author of commit.commit.authors.nodes) { /** * @note In some situations, GitHub will return "user: null" * for the commit user. Nobody to add to the authors then. */ if (author.user != null) { addAuthor(author.user.login) } } } resolve() }) queue.push( authorLoginPromise.catch((error: Error) => { log.error( format( 'Failed to extract the authors for the issue #%d:', issueId, error.message, ), ) }), ) } // Extract author GitHub handles in parallel. await Promise.allSettled(queue) return authors }