mirror of
https://github.com/kiegroup/git-backporting.git
synced 2025-06-28 05:33:47 +00:00
feat: pull request backporting
feat: backport still open pull requests
This commit is contained in:
commit
b3936e019a
53 changed files with 48467 additions and 0 deletions
90
test/service/args/cli/cli-args-parser.test.ts
Normal file
90
test/service/args/cli/cli-args-parser.test.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { Args } from "@bp/service/args/args.types";
|
||||
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
||||
import { addProcessArgs, resetProcessArgs } from "../../../support/utils";
|
||||
|
||||
describe("cli args parser", () => {
|
||||
let parser: CLIArgsParser;
|
||||
|
||||
beforeEach(() => {
|
||||
// create a fresh new instance every time
|
||||
parser = new CLIArgsParser();
|
||||
|
||||
// reset process.env variables
|
||||
resetProcessArgs();
|
||||
});
|
||||
|
||||
test("valid execution [default, short]", () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://localhost/whatever/pulls/1"
|
||||
]);
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(false);
|
||||
expect(args.auth).toEqual("");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
test("valid execution [default, long]", () => {
|
||||
addProcessArgs([
|
||||
"--target-branch",
|
||||
"target",
|
||||
"--pull-request",
|
||||
"https://localhost/whatever/pulls/1"
|
||||
]);
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(false);
|
||||
expect(args.auth).toEqual("");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
test("valid execution [override, short]", () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-a",
|
||||
"bearer-token",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://localhost/whatever/pulls/1"
|
||||
]);
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(true);
|
||||
expect(args.auth).toEqual("bearer-token");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
test("valid execution [override, long]", () => {
|
||||
addProcessArgs([
|
||||
"--dry-run",
|
||||
"--auth",
|
||||
"bearer-token",
|
||||
"--target-branch",
|
||||
"target",
|
||||
"--pull-request",
|
||||
"https://localhost/whatever/pulls/1"
|
||||
]);
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(true);
|
||||
expect(args.auth).toEqual("bearer-token");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
});
|
50
test/service/args/gha/gha-args-parser.test.ts
Normal file
50
test/service/args/gha/gha-args-parser.test.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { Args } from "@bp/service/args/args.types";
|
||||
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
||||
import { spyGetInput } from "../../../support/utils";
|
||||
|
||||
describe("gha args parser", () => {
|
||||
let parser: GHAArgsParser;
|
||||
|
||||
beforeEach(() => {
|
||||
// create a fresh new instance every time
|
||||
parser = new GHAArgsParser();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
|
||||
test("valid execution [default]", () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://localhost/whatever/pulls/1"
|
||||
});
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(false);
|
||||
expect(args.auth).toEqual("");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
test("valid execution [override]", () => {
|
||||
spyGetInput({
|
||||
"dry-run": "true",
|
||||
"auth": "bearer-token",
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://localhost/whatever/pulls/1"
|
||||
});
|
||||
|
||||
const args: Args = parser.parse();
|
||||
expect(args.dryRun).toEqual(true);
|
||||
expect(args.auth).toEqual("bearer-token");
|
||||
expect(args.author).toEqual(undefined);
|
||||
expect(args.folder).toEqual(undefined);
|
||||
expect(args.targetBranch).toEqual("target");
|
||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||
});
|
||||
|
||||
});
|
177
test/service/configs/pullrequest/pr-configs-parser.test.ts
Normal file
177
test/service/configs/pullrequest/pr-configs-parser.test.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
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 GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import { GitServiceType } from "@bp/service/git/git.types";
|
||||
import { setupMoctokit } from "../../../support/moctokit/moctokit-support";
|
||||
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner } from "../../../support/moctokit/moctokit-data";
|
||||
|
||||
describe("pull request config parser", () => {
|
||||
|
||||
const mergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`;
|
||||
const openPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${openPullRequestFixture.number}`;
|
||||
const notMergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${notMergedPullRequestFixture.number}`;
|
||||
|
||||
let parser: PullRequestConfigsParser;
|
||||
|
||||
beforeAll(() => {
|
||||
GitServiceFactory.init(GitServiceType.GITHUB, "whatever");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
|
||||
parser = new PullRequestConfigsParser();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test("parse configs from pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: false,
|
||||
auth: "",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod"
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(false);
|
||||
expect(configs.author).toEqual("gh-user");
|
||||
expect(configs.auth).toEqual("");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 2368,
|
||||
author: "gh-user",
|
||||
url: "https://api.github.com/repos/owner/reponame/pulls/2368",
|
||||
htmlUrl: "https://github.com/owner/reponame/pull/2368",
|
||||
state: "closed",
|
||||
merged: true,
|
||||
mergedBy: "that-s-a-user",
|
||||
title: "PR Title",
|
||||
body: "Please review and merge",
|
||||
reviewers: ["requested-gh-user", "gh-user"],
|
||||
targetRepo: {
|
||||
owner: "owner",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/owner/reponame.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "fork",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/fork/reponame.git"
|
||||
},
|
||||
nCommits: 2,
|
||||
commits: ["28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc"]
|
||||
});
|
||||
expect(configs.backportPullRequest).toEqual({
|
||||
author: "gh-user",
|
||||
url: undefined,
|
||||
htmlUrl: undefined,
|
||||
title: "[prod] PR Title",
|
||||
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).",
|
||||
reviewers: ["gh-user", "that-s-a-user"],
|
||||
targetRepo: {
|
||||
owner: "owner",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/owner/reponame.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "owner",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/owner/reponame.git"
|
||||
},
|
||||
nCommits: 0,
|
||||
commits: []
|
||||
});
|
||||
});
|
||||
|
||||
test("override folder", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
folder: "/tmp/test"
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual("/tmp/test");
|
||||
});
|
||||
|
||||
test("override author", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
author: "another-user"
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.author).toEqual("another-user");
|
||||
});
|
||||
|
||||
test("still open pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: openPRUrl,
|
||||
targetBranch: "prod"
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.author).toEqual("gh-user");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 4444,
|
||||
author: "gh-user",
|
||||
url: "https://api.github.com/repos/owner/reponame/pulls/4444",
|
||||
htmlUrl: "https://github.com/owner/reponame/pull/4444",
|
||||
state: "open",
|
||||
merged: false,
|
||||
mergedBy: "that-s-a-user",
|
||||
title: "PR Title",
|
||||
body: "Please review and merge",
|
||||
reviewers: ["gh-user"],
|
||||
targetRepo: {
|
||||
owner: "owner",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/owner/reponame.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "fork",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/fork/reponame.git"
|
||||
},
|
||||
nCommits: 2,
|
||||
// taken from head.sha
|
||||
commits: ["91748965051fae1330ad58d15cf694e103267c87"]
|
||||
});
|
||||
});
|
||||
|
||||
test("closed pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: notMergedPRUrl,
|
||||
targetBranch: "prod"
|
||||
};
|
||||
|
||||
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
});
|
114
test/service/git/git-cli.test.ts
Normal file
114
test/service/git/git-cli.test.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import { FileState, GitActionTypes, MockGithub } from "@kie/mock-github";
|
||||
import { spawnSync } from "child_process";
|
||||
import { assert } from "console";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
let git: GitCLIService;
|
||||
let cwd: string;
|
||||
let currentBranch: string;
|
||||
let pushedBranches: string[];
|
||||
let localBranches: string[];
|
||||
let files: FileState[];
|
||||
|
||||
const mockGithub = new MockGithub(
|
||||
{
|
||||
repo: {
|
||||
repoA: {
|
||||
pushedBranches: ["sbranch", "tbranch"],
|
||||
localBranches: ["lbranch"],
|
||||
currentBranch: "main",
|
||||
history: [
|
||||
{
|
||||
action: GitActionTypes.PUSH,
|
||||
branch: "main",
|
||||
},
|
||||
{
|
||||
action: GitActionTypes.PUSH,
|
||||
branch: "sbranch",
|
||||
},
|
||||
{
|
||||
action: GitActionTypes.PUSH,
|
||||
branch: "tbranch",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
path.join(__dirname, "setup-cli")
|
||||
);
|
||||
|
||||
beforeAll(async () => {
|
||||
//setup
|
||||
await mockGithub.setup();
|
||||
cwd = mockGithub.repo.getPath("repoA")!;
|
||||
currentBranch = mockGithub.repo.getBranchState("repoA")!.currentBranch;
|
||||
pushedBranches = mockGithub.repo.getBranchState("repoA")!.pushedBranches;
|
||||
localBranches = mockGithub.repo.getBranchState("repoA")!.localBranches;
|
||||
files = (await mockGithub.repo.getFileSystemState("repoA"))!;
|
||||
|
||||
//make sure the setup is correct to run this test suite
|
||||
assert(
|
||||
pushedBranches.length > 1,
|
||||
"your configuration must have a repository with pushed branches other than main"
|
||||
);
|
||||
assert(
|
||||
localBranches.length > 0,
|
||||
"your configuration must have a repository with local branches i.e. not pushed branches"
|
||||
);
|
||||
assert(
|
||||
files.length > 0,
|
||||
"your configuration needs at least 1 file committed to some branch which is not the current branch"
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await mockGithub.teardown();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// create a fresh instance of git before each test
|
||||
git = new GitCLIService("", "author");
|
||||
});
|
||||
|
||||
describe("git cli service", () => {
|
||||
test("version", async () => {
|
||||
const result = await git.version(cwd);
|
||||
const actualVersion = spawnSync("git", ["version"]).stdout.toString();
|
||||
const match = actualVersion.match(/(\d+\.\d+(\.\d+)?)/);
|
||||
if (match) {
|
||||
expect(result).toEqual(match[1]);
|
||||
} else {
|
||||
expect(result).toBe(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
test("fetch", async () => {
|
||||
await expect(git.fetch(cwd, currentBranch)).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
test("local branch", async () => {
|
||||
await expect(git.createLocalBranch(cwd, "new-local-branch")).resolves.not.toThrowError();
|
||||
|
||||
// use rev-parse to double check the current branch is the new one
|
||||
const output = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd }).stdout.toString().trim();
|
||||
expect(output).toEqual("new-local-branch");
|
||||
});
|
||||
|
||||
test("push local branch", async () => {
|
||||
const expressionToTest = "GIT_CHERRY_SHOULD_NOT_INCLUDE_THIS_MSG";
|
||||
// create file to push
|
||||
fs.writeFileSync(path.join(cwd, "test-push"), "testing git push");
|
||||
|
||||
// add and commit the file
|
||||
spawnSync("git", ["add", "."], { cwd });
|
||||
spawnSync("git", ["commit", "-m", expressionToTest], { cwd });
|
||||
|
||||
await git.push(cwd, currentBranch, "origin", false);
|
||||
|
||||
// use git cherry to verify this commit was pushed
|
||||
const output = spawnSync("git", ["cherry", "-v"], { cwd }).stdout.toString();
|
||||
expect(output.includes(expressionToTest)).toBe(false);
|
||||
});
|
||||
});
|
40
test/service/git/github/github-service.test.ts
Normal file
40
test/service/git/github/github-service.test.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import { GitPullRequest, GitServiceType } from "@bp/service/git/git.types";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import { mergedPullRequestFixture, repo, targetOwner } from "../../../support/moctokit/moctokit-data";
|
||||
import { setupMoctokit } from "../../../support/moctokit/moctokit-support";
|
||||
|
||||
describe("github service", () => {
|
||||
|
||||
let gitService: GitHubService;
|
||||
|
||||
beforeAll(() => {
|
||||
// init git service
|
||||
GitServiceFactory.init(GitServiceType.GITHUB, "whatever");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// mock github api calls
|
||||
setupMoctokit();
|
||||
|
||||
gitService = GitServiceFactory.getService() as GitHubService;
|
||||
});
|
||||
|
||||
test("get pull request: success", async () => {
|
||||
const res: GitPullRequest = await gitService.getPullRequest(targetOwner, repo, mergedPullRequestFixture.number);
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "fork",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/fork/reponame.git"
|
||||
});
|
||||
expect(res.targetRepo).toEqual({
|
||||
owner: "owner",
|
||||
project: "reponame",
|
||||
cloneUrl: "https://github.com/owner/reponame.git"
|
||||
});
|
||||
expect(res.title).toBe("PR Title");
|
||||
expect(res.commits.length).toBe(1);
|
||||
expect(res.commits).toEqual(["28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc"]);
|
||||
});
|
||||
|
||||
});
|
285
test/service/runner/cli-runner.test.ts
Normal file
285
test/service/runner/cli-runner.test.ts
Normal file
|
@ -0,0 +1,285 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
||||
import { addProcessArgs, resetProcessArgs } from "../../support/utils";
|
||||
import { setupMoctokit } from "../../support/moctokit/moctokit-support";
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitHubService.prototype, "createPullRequest");
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
|
||||
// create CLI arguments parser
|
||||
parser = new CLIArgsParser();
|
||||
|
||||
// create runner
|
||||
runner = new Runner(parser);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
// reset process.env variables
|
||||
resetProcessArgs();
|
||||
});
|
||||
|
||||
describe("cli runner", () => {
|
||||
test("with dry run", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/2368"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("overriding author", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/2368"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("with relative folder", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/2368",
|
||||
"-f",
|
||||
"folder"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/folder";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("with absolute folder", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/2368",
|
||||
"-f",
|
||||
"/tmp/folder"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = "/tmp/folder";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/2368"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/2368"),
|
||||
reviewers: ["gh-user", "that-s-a-user"]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("same owner", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/8632"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/8632"),
|
||||
reviewers: ["gh-user", "that-s-a-user"]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("closed and not merged pull request", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/6666"
|
||||
]);
|
||||
|
||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
|
||||
test("open pull request", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/4444"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-91748965051fae1330ad58d15cf694e103267c87",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/4444"),
|
||||
reviewers: ["gh-user", "that-s-a-user"]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
141
test/service/runner/gha-runner.test.ts
Normal file
141
test/service/runner/gha-runner.test.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
||||
import { spyGetInput } from "../../support/utils";
|
||||
import { setupMoctokit } from "../../support/moctokit/moctokit-support";
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitHubService.prototype, "createPullRequest");
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
|
||||
// create GHA arguments parser
|
||||
parser = new GHAArgsParser();
|
||||
|
||||
// create runner
|
||||
runner = new Runner(parser);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("gha runner", () => {
|
||||
test("with dry run", async () => {
|
||||
spyGetInput({
|
||||
"dry-run": "true",
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://github.com/owner/reponame/pull/2368"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://github.com/owner/reponame/pull/2368"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/2368"),
|
||||
reviewers: ["gh-user", "that-s-a-user"]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("closed and not merged pull request", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://github.com/owner/reponame/pull/6666"
|
||||
});
|
||||
|
||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
|
||||
test("open pull request", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://github.com/owner/reponame/pull/4444"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-91748965051fae1330ad58d15cf694e103267c87",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/4444"),
|
||||
reviewers: ["gh-user", "that-s-a-user"]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
1816
test/support/moctokit/moctokit-data.ts
Normal file
1816
test/support/moctokit/moctokit-data.ts
Normal file
File diff suppressed because it is too large
Load diff
89
test/support/moctokit/moctokit-support.ts
Normal file
89
test/support/moctokit/moctokit-support.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { Moctokit } from "@kie/mock-github";
|
||||
import { targetOwner, repo, mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, notFoundPullRequestNumber, sameOwnerPullRequestFixture } from "./moctokit-data";
|
||||
|
||||
const logger = LoggerServiceFactory.getLogger();
|
||||
|
||||
export const setupMoctokit = (): Moctokit => {
|
||||
logger.debug("Setting up moctokit.");
|
||||
|
||||
const mock = new Moctokit();
|
||||
|
||||
// setup the mock requests here
|
||||
|
||||
// valid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: mergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: sameOwnerPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: sameOwnerPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: openPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: openPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notMergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: notMergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.create()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.requestReviewers()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
|
||||
// invalid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notFoundPullRequestNumber
|
||||
})
|
||||
.reply({
|
||||
status: 404,
|
||||
data: {
|
||||
message: "Not found"
|
||||
}
|
||||
});
|
||||
|
||||
return mock;
|
||||
};
|
17
test/support/utils.ts
Normal file
17
test/support/utils.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as core from "@actions/core";
|
||||
|
||||
export const addProcessArgs = (args: string[]) => {
|
||||
process.argv = [...process.argv, ...args];
|
||||
};
|
||||
|
||||
export const resetProcessArgs = () => {
|
||||
process.argv = ["node", "backporting"];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const spyGetInput = (obj: any) => {
|
||||
const mock = jest.spyOn(core, "getInput");
|
||||
mock.mockImplementation((name: string) : string => {
|
||||
return obj[name];
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue