backport
Version:
A CLI tool that automates the process of backporting commits
152 lines (147 loc) • 5.45 kB
JavaScript
/** Parses raw GitHub API commit data into the Commit type used throughout the codebase. */
import { differenceBy } from 'lodash-es';
import { graphql } from '../../graphql/generated/index.js';
import { filterNil } from '../../utils/filter-empty.js';
import { parseRemoteConfigFile } from '../remote-config.js';
import { getPullRequestStates } from './get-pull-request-states.js';
import { getSourcePullRequest } from './get-source-pull-request.js';
function getSuggestedTargetBranches(sourceCommit, targetPullRequestStates, branchLabelMapping) {
const missingPrs = getPullRequestStates({
sourceCommit,
branchLabelMapping,
}).filter((pr) => pr.state === 'NOT_CREATED' || pr.state === 'CLOSED');
const mergedPrs = targetPullRequestStates.filter((pr) => pr.state === 'MERGED');
return differenceBy(missingPrs, mergedPrs, (pr) => pr.label).map((pr) => pr.branch);
}
export function parseSourceCommit({ sourceCommit, options, }) {
const sourcePullRequest = getSourcePullRequest(sourceCommit);
const sourceCommitBranchLabelMapping = getSourceCommitBranchLabelMapping(sourceCommit);
const branchLabelMapping = sourceCommitBranchLabelMapping ?? options.branchLabelMapping;
const targetPullRequestStates = getPullRequestStates({
sourceCommit,
branchLabelMapping,
});
const suggestedTargetBranches = getSuggestedTargetBranches(sourceCommit, targetPullRequestStates, options.branchLabelMapping);
return {
author: sourceCommit.author,
sourceCommit: {
committedDate: String(sourceCommit.committedDate),
message: sourceCommit.message,
sha: String(sourceCommit.sha),
branchLabelMapping: sourceCommitBranchLabelMapping,
},
sourcePullRequest: sourcePullRequest
? {
labels: sourcePullRequest.labels?.nodes
?.map((label) => label?.name)
.filter(filterNil) ?? [],
title: sourcePullRequest.title,
number: sourcePullRequest.number,
url: String(sourcePullRequest.url),
mergeCommit: sourcePullRequest.mergeCommit
? {
message: sourcePullRequest.mergeCommit.message,
sha: String(sourcePullRequest.mergeCommit.sha),
}
: undefined,
}
: undefined,
sourceBranch: sourcePullRequest?.baseRefName ?? options.sourceBranch,
suggestedTargetBranches,
targetPullRequestStates: targetPullRequestStates,
};
}
export const SourceCommitWithTargetPullRequestFragment = graphql(`
fragment SourceCommitWithTargetPullRequestFragment on Commit {
__typename
# Source Commit
repository {
name
owner {
login
}
}
sha: oid
message
committedDate
author {
name
email
}
# Source pull request: PR where source commit was merged in.
# first: 20 disambiguates when multiple PRs' head branches contain the SHA.
associatedPullRequests(first: 20) {
edges {
node {
title
url
number
labels(first: 50) {
nodes {
name
}
}
baseRefName
# source merge commit (the commit that actually went into the source branch)
mergeCommit {
__typename
...RemoteConfigHistoryFragment
sha: oid
message
}
# (possible) backport pull requests referenced in the source pull request
timelineItems(last: 20, itemTypes: CROSS_REFERENCED_EVENT) {
edges {
node {
... on CrossReferencedEvent {
__typename
targetPullRequest: source {
__typename
# Target PRs (backport PRs)
... on PullRequest {
__typename
# target merge commit: the backport commit that was merged into the target branch
targetMergeCommit: mergeCommit {
sha: oid
message
}
repository {
name
owner {
login
}
}
url
title
state
baseRefName
number
commits(first: 20) {
edges {
node {
targetCommit: commit {
message
sha: oid
}
}
}
}
}
}
}
}
}
}
}
}
}
}
`);
function getSourceCommitBranchLabelMapping(sourceCommit) {
const sourcePullRequest = getSourcePullRequest(sourceCommit);
const remoteConfig = sourcePullRequest?.mergeCommit?.remoteConfigHistory.edges?.at(0)?.remoteConfig;
if (remoteConfig) {
return parseRemoteConfigFile(remoteConfig)?.branchLabelMapping;
}
}
//# sourceMappingURL=parse-source-commit.js.map