@ossjs/release
Version:
Minimalistic, opinionated, and predictable release automation tool.
83 lines (68 loc) • 2.33 kB
text/typescript
import createIssueParser from 'issue-parser'
import { getInfo, type GitInfo } from '#/src/utils/git/get-info.js'
import type { ParsedCommitWithHash } from '#/src/utils/git/parse-commits.js'
const parser = createIssueParser('github')
function extractIssueIds(text: string, repo: GitInfo): Set<string> {
const ids = new Set<string>()
const parsed = parser(text)
for (const action of parsed.actions.close) {
if (action.slug == null || action.slug === `${repo.owner}/${repo.name}`) {
ids.add(action.issue)
}
}
return ids
}
export async function getReleaseRefs(
commits: ParsedCommitWithHash[],
): Promise<Set<string>> {
const repo = await getInfo()
const issueIds = new Set<string>()
for (const commit of commits) {
// Extract issue ids from the commit messages.
for (const ref of commit.references) {
if (ref.issue) {
issueIds.add(ref.issue)
}
}
// Extract issue ids from the commit bodies.
if (commit.body) {
const bodyIssueIds = extractIssueIds(commit.body, repo)
bodyIssueIds.forEach((id) => issueIds.add(id))
}
}
// Fetch issue detail from each issue referenced in the commit message
// or commit body. Those may include pull request ids that reference
// other issues.
const issuesFromCommits = await Promise.all(
Array.from(issueIds).map(fetchIssue),
)
// Extract issue ids from the pull request descriptions.
for (const issue of issuesFromCommits) {
// Ignore regular issues as they may not close/fix other issues
// by reference (at least on GitHub).
if (!issue.pull_request || !issue.body) {
continue
}
const descriptionIssueIds = extractIssueIds(issue.body, repo)
descriptionIssueIds.forEach((id) => issueIds.add(id))
}
return issueIds
}
export interface IssueOrPullRequest {
html_url: string
pull_request: Record<string, string> | null
body: string | null
}
async function fetchIssue(id: string): Promise<IssueOrPullRequest> {
const repo = await getInfo()
const response = await fetch(
`https://api.github.com/repos/${repo.owner}/${repo.name}/issues/${id}`,
{
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
},
},
)
const resource = (await response.json()) as Promise<IssueOrPullRequest>
return resource
}