backport
Version:
A CLI tool that automates the process of backporting commits
121 lines • 4.74 kB
JavaScript
import { isEmpty, first, uniqBy, orderBy } from 'lodash-es';
import { graphql } from '../../../../graphql/generated/index.js';
import { filterNil } from '../../../../utils/filter-empty.js';
import { filterUnmergedCommits } from '../../../../utils/filter-unmerged-commits.js';
import { BackportError } from '../../../backport-error.js';
import { isMissingConfigFileException } from '../../../remote-config.js';
import { parseSourceCommit } from '../../../sourceCommit/parse-source-commit.js';
import { graphqlRequest } from '../client/graphql-client.js';
import { fetchAuthorId } from '../fetch-author-id.js';
async function fetchByCommitPath({ options, authorId, commitPath, }) {
const { githubToken, since, until, githubApiBaseUrlV4 = 'https://api.github.com/graphql', maxCount = 10, repoName, repoOwner, sourceBranch, } = options;
const query = graphql(`
query CommitsByAuthor(
$authorId: ID
$commitPath: String
$since: GitTimestamp
$until: GitTimestamp
$maxCount: Int!
$repoName: String!
$repoOwner: String!
$sourceBranch: String!
) {
repository(owner: $repoOwner, name: $repoName) {
ref(qualifiedName: $sourceBranch) {
target {
... on Commit {
__typename
history(
first: $maxCount
author: { id: $authorId }
path: $commitPath
since: $since
until: $until
) {
edges {
node {
__typename
...SourceCommitWithTargetPullRequestFragment
}
}
}
}
}
}
}
}
`);
const variables = {
repoOwner,
repoName,
sourceBranch,
maxCount,
authorId,
commitPath,
since,
until,
};
const result = await graphqlRequest({ githubToken, githubApiBaseUrlV4 }, query, variables);
if (result.error) {
if (result.statusCode === 502 && maxCount > 50) {
throw new BackportError({
code: 'github-api-exception',
message: `The GitHub API returned a 502 error. Try reducing the number of commits to display: "--max-count 20" (or "-n 20")`,
});
}
if (!isMissingConfigFileException(result)) {
throw new BackportError({
code: 'github-api-exception',
message: result.error.message,
});
}
}
return result.data;
}
export async function fetchCommitsByAuthor(options) {
const { sourceBranch, commitPaths = [] } = options;
const authorId = await fetchAuthorId(options);
const allResponses = await Promise.all(isEmpty(commitPaths)
? [fetchByCommitPath({ options, authorId, commitPath: null })]
: commitPaths.map((commitPath) => fetchByCommitPath({ options, authorId, commitPath })));
const responses = allResponses.filter(filterNil);
// we only need to check if the first item is `null` (if the first is `null` they all are)
if (first(responses)?.repository?.ref === null) {
throw new BackportError({
code: 'branch-not-found-exception',
branchName: sourceBranch,
});
}
const commits = responses
.flatMap((res) => {
const repoRefTarget = res.repository?.ref?.target;
if (repoRefTarget?.__typename !== 'Commit') {
return;
}
return repoRefTarget.history.edges?.map((edge) => {
const sourceCommit = edge?.node;
if (sourceCommit) {
return parseSourceCommit({ options, sourceCommit });
}
});
})
.filter(filterNil);
// terminate if not commits were found
if (isEmpty(commits)) {
const pathText = commitPaths.length > 0 ? ` touching files in path: "${commitPaths}"` : '';
const errorText = options.author
? `There are no commits by "${options.author}" in this repository${pathText}. Try with \`--all\` for commits by all users or \`--author=<username>\` for commits from a specific user`
: `There are no commits in this repository${pathText}`;
throw new BackportError({
code: 'no-commits-found-exception',
message: errorText,
});
}
const commitsUnique = uniqBy(commits, (c) => c.sourceCommit.sha);
const commitsSorted = orderBy(commitsUnique, (c) => c.sourceCommit.committedDate, 'desc');
if (options.onlyMissing) {
return commitsSorted.filter(filterUnmergedCommits);
}
return commitsSorted;
}
//# sourceMappingURL=fetch-commits-by-author.js.map