git-backporting/test/service/configs/pullrequest/github-pr-configs-parser-multiple.test.ts
Earl Warren 6042bcc40b
feat: auto-detect the value of the no-squash option (#118)
The auto-no-squash option is added to:

* backport all the commits when the pull/merge request has been merged
* backport the squashed commit otherwise

It is equivalent to dynamically adjust the value of the no-squash
option, depending on the context.

The no-squash option is kept for backward compatibility for a single
use case: backporting the merged commit instead of backporting the
commits of the pull/merge request request.

Detecting if a pull/merge request was squashed or not depends on the
underlying forge:

* Forgejo / GitHub: use the API to count the number of parents
* GitLab: if the squash_commit_sha is set, the merge request was
  squashed

If the pull/merge request is open, always backport all the commits it
contains.

Fixes: https://github.com/kiegroup/git-backporting/issues/113

Co-authored-by: Andrea Lamparelli <a.lamparelli95@gmail.com>
2024-04-08 18:51:13 +02:00

493 lines
No EOL
16 KiB
TypeScript

import { Args } from "@bp/service/args/args.types";
import { Configs } from "@bp/service/configs/configs.types";
import PullRequestConfigsParser from "@bp/service/configs/pullrequest/pr-configs-parser";
import GitClientFactory from "@bp/service/git/git-client-factory";
import { GitClientType } from "@bp/service/git/git.types";
import { mockGitHubClient } from "../../../support/mock/git-client-mock-support";
import { resetProcessArgs } from "../../../support/utils";
import { MERGED_PR_FIXTURE, REPO, TARGET_OWNER, MULT_COMMITS_PR_FIXTURE } from "../../../support/mock/github-data";
import GitHubMapper from "@bp/service/git/github/github-mapper";
import GitHubClient from "@bp/service/git/github/github-client";
jest.spyOn(GitHubMapper.prototype, "mapPullRequest");
jest.spyOn(GitHubClient.prototype, "getPullRequest");
describe("github pull request config parser", () => {
const mergedPRUrl = `https://github.com/${TARGET_OWNER}/${REPO}/pull/${MERGED_PR_FIXTURE.number}`;
const multipleCommitsPRUrl = `https://github.com/${TARGET_OWNER}/${REPO}/pull/${MULT_COMMITS_PR_FIXTURE.number}`;
let configParser: PullRequestConfigsParser;
beforeAll(() => {
GitClientFactory.reset();
GitClientFactory.getOrCreate(GitClientType.GITHUB, "whatever", "http://localhost/api/v3");
});
beforeEach(() => {
// reset process.env variables
resetProcessArgs();
// mock octokit
mockGitHubClient("http://localhost/api/v3");
// create a fresh new instance every time
configParser = new PullRequestConfigsParser();
});
test("multiple backports", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: mergedPRUrl,
targetBranch: "v1, v2, v3",
gitUser: "Me",
gitEmail: "me@email.com",
title: "New Title",
body: "New Body",
bodyPrefix: "New Body Prefix -",
reviewers: [],
assignees: ["user3", "user4"],
inheritReviewers: false,
labels: [],
inheritLabels: false,
comments: [],
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
expect(configs.dryRun).toEqual(false);
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "bp-v1-28f63db",
base: "v1",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v2-28f63db",
base: "v2",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v3-28f63db",
base: "v3",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
])
);
});
test("multiple backports ignore duplicates", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: mergedPRUrl,
targetBranch: "v1, v2, v2, v3",
gitUser: "Me",
gitEmail: "me@email.com",
title: "New Title",
body: "New Body",
bodyPrefix: "New Body Prefix -",
reviewers: [],
assignees: ["user3", "user4"],
inheritReviewers: false,
labels: [],
inheritLabels: false,
comments: [],
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
expect(configs.dryRun).toEqual(false);
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "bp-v1-28f63db",
base: "v1",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v2-28f63db",
base: "v2",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v3-28f63db",
base: "v3",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
])
);
});
test("multiple backports with custom branch name", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: mergedPRUrl,
targetBranch: "v1, v2, v3",
gitUser: "Me",
gitEmail: "me@email.com",
title: "New Title",
body: "New Body",
bodyPrefix: "New Body Prefix -",
reviewers: [],
assignees: ["user3", "user4"],
inheritReviewers: false,
labels: [],
inheritLabels: false,
comments: [],
bpBranchName: "custom-branch",
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
expect(configs.dryRun).toEqual(false);
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "custom-branch-v1",
base: "v1",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "custom-branch-v2",
base: "v2",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "custom-branch-v3",
base: "v3",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
])
);
});
test("multiple backports with multiple custom branch names", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: mergedPRUrl,
targetBranch: "v1, v2, v3",
gitUser: "Me",
gitEmail: "me@email.com",
title: "New Title",
body: "New Body",
bodyPrefix: "New Body Prefix -",
reviewers: [],
assignees: ["user3", "user4"],
inheritReviewers: false,
labels: [],
inheritLabels: false,
comments: [],
bpBranchName: "custom-branch1, custom-branch2, custom-branch3",
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
expect(configs.dryRun).toEqual(false);
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "custom-branch1",
base: "v1",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "custom-branch2",
base: "v2",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "custom-branch3",
base: "v3",
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
labels: [],
comments: [],
},
])
);
});
test("multiple backports with incorrect number of bp branch names", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: mergedPRUrl,
targetBranch: "v1, v2, v3",
gitUser: "Me",
gitEmail: "me@email.com",
title: "New Title",
body: "New Body",
bodyPrefix: "New Body Prefix -",
reviewers: [],
assignees: ["user3", "user4"],
inheritReviewers: false,
labels: [],
inheritLabels: false,
comments: [],
bpBranchName: "custom-branch1, custom-branch2",
};
await expect(() => configParser.parseAndValidate(args)).rejects.toThrow("The number of backport branch names, if provided, must match the number of target branches or just one, provided 2 branch names instead");
});
test("multiple backports and multiple commits", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: multipleCommitsPRUrl,
targetBranch: "v4, v5, v6",
gitUser: "GitHub",
gitEmail: "noreply@github.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
squash: false,
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 8632, false);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "GitHub",
email: "noreply@github.com"
});
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "bp-v4-0404fb9-11da4e3",
base: "v4",
title: "[v4] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v5-0404fb9-11da4e3",
base: "v5",
title: "[v5] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v6-0404fb9-11da4e3",
base: "v6",
title: "[v6] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
])
);
});
test("multiple extracted branches and multiple commits", async () => {
const args: Args = {
dryRun: false,
auth: "",
pullRequest: multipleCommitsPRUrl,
targetBranchPattern: "^backport (?<target>([^ ]+))$",
gitUser: "GitHub",
gitEmail: "noreply@github.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
squash: false,
};
const configs: Configs = await configParser.parseAndValidate(args);
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 8632, false);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "GitHub",
email: "noreply@github.com"
});
expect(configs.auth).toEqual("");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.backportPullRequests.length).toEqual(3);
expect(configs.backportPullRequests).toEqual(
expect.arrayContaining([
{
owner: "owner",
repo: "reponame",
head: "bp-v1-0404fb9-11da4e3",
base: "v1",
title: "[v1] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v2-0404fb9-11da4e3",
base: "v2",
title: "[v2] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
{
owner: "owner",
repo: "reponame",
head: "bp-v3-0404fb9-11da4e3",
base: "v3",
title: "[v3] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
labels: [],
comments: [],
},
])
);
});
});