feat: config file as option (#42)

Fix https://github.com/lampajr/backporting/issues/37

This enhancement required a huge refactoring where all arguments
defaults have been centralized in one single place ArgsParser#parse
This commit is contained in:
Andrea Lamparelli 2023-07-05 22:11:23 +02:00 committed by GitHub
parent a88adeec35
commit 5ead31f606
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1465 additions and 219 deletions

View file

@ -4,7 +4,31 @@ import PullRequestConfigsParser from "@bp/service/configs/pullrequest/pr-configs
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 { addProcessArgs, createTestFile, removeTestFile, resetProcessArgs } from "../../../support/utils";
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner } from "../../../support/mock/github-data";
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./github-pr-configs-parser-simple-pr-merged.json";
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
"targetBranch": "prod",
"pullRequest": `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`,
};
const GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME = "./github-pr-configs-parser-complex-pr-merged.json";
const GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT = {
"dryRun": false,
"auth": "my-auth-token",
"pullRequest": `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`,
"targetBranch": "prod",
"gitUser": "Me",
"gitEmail": "me@email.com",
"title": "New Title",
"body": "New Body",
"bodyPrefix": "New Body Prefix -",
"reviewers": ["user1", "user2"],
"assignees": ["user3", "user4"],
"inheritReviewers": true, // not taken into account
};
describe("github pull request config parser", () => {
@ -12,17 +36,33 @@ describe("github pull request config parser", () => {
const openPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${openPullRequestFixture.number}`;
const notMergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${notMergedPullRequestFixture.number}`;
let parser: PullRequestConfigsParser;
let argsParser: CLIArgsParser;
let configParser: PullRequestConfigsParser;
beforeAll(() => {
// create a temporary file
createTestFile(GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME, JSON.stringify(GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT));
createTestFile(GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME, JSON.stringify(GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT));
GitClientFactory.reset();
GitClientFactory.getOrCreate(GitClientType.GITHUB, "whatever", "http://localhost/api/v3");
});
afterAll(() => {
// clean up all temporary files
removeTestFile(GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME);
removeTestFile(GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME);
});
beforeEach(() => {
mockGitHubClient("http://localhost/api/v3");
parser = new PullRequestConfigsParser();
// reset process.env variables
resetProcessArgs();
// create a fresh new instance every time
argsParser = new CLIArgsParser();
configParser = new PullRequestConfigsParser();
});
afterEach(() => {
@ -42,7 +82,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -113,7 +153,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(true);
expect(configs.auth).toEqual("whatever");
@ -138,7 +178,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(true);
expect(configs.auth).toEqual("whatever");
@ -189,7 +229,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true,
};
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
expect(async () => await configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
});
@ -209,7 +249,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -283,7 +323,7 @@ describe("github pull request config parser", () => {
inheritReviewers: true, // not taken into account
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -357,7 +397,7 @@ describe("github pull request config parser", () => {
inheritReviewers: false,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -414,4 +454,133 @@ describe("github pull request config parser", () => {
bpBranchName: undefined,
});
});
test("using simple config file", async () => {
addProcessArgs([
"-cf",
GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME,
]);
const args: Args = argsParser.parse();
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "GitHub",
email: "noreply@github.com"
});
expect(configs.auth).toEqual(undefined);
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"],
assignees: [],
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: "GitHub",
url: undefined,
htmlUrl: undefined,
title: "[prod] PR Title",
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
reviewers: ["gh-user", "that-s-a-user"],
assignees: [],
targetRepo: {
owner: "owner",
project: "reponame",
cloneUrl: "https://github.com/owner/reponame.git"
},
sourceRepo: {
owner: "owner",
project: "reponame",
cloneUrl: "https://github.com/owner/reponame.git"
},
bpBranchName: undefined,
});
});
test("using complex config file", async () => {
addProcessArgs([
"-cf",
GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME,
]);
const args: Args = argsParser.parse();
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "Me",
email: "me@email.com"
});
expect(configs.auth).toEqual("my-auth-token");
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"],
assignees: [],
targetRepo: {
owner: "owner",
project: "reponame",
cloneUrl: "https://github.com/owner/reponame.git"
},
sourceRepo: {
owner: "fork",
project: "reponame",
cloneUrl: "https://github.com/fork/reponame.git"
},
bpBranchName: undefined,
nCommits: 2,
commits: ["28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc"],
});
expect(configs.backportPullRequest).toEqual({
author: "Me",
url: undefined,
htmlUrl: undefined,
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: ["user1", "user2"],
assignees: ["user3", "user4"],
targetRepo: {
owner: "owner",
project: "reponame",
cloneUrl: "https://github.com/owner/reponame.git"
},
sourceRepo: {
owner: "owner",
project: "reponame",
cloneUrl: "https://github.com/owner/reponame.git"
},
bpBranchName: undefined,
});
});
});

View file

@ -5,6 +5,31 @@ import GitClientFactory from "@bp/service/git/git-client-factory";
import { GitClientType } from "@bp/service/git/git.types";
import { getAxiosMocked } from "../../../support/mock/git-client-mock-support";
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR } from "../../../support/mock/gitlab-data";
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
import { createTestFile, removeTestFile, spyGetInput } from "../../../support/utils";
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./gitlab-pr-configs-parser-simple-pr-merged.json";
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
"targetBranch": "prod",
"pullRequest": `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${MERGED_SQUASHED_MR.iid}`,
};
const GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME = "./gitlab-pr-configs-parser-complex-pr-merged.json";
const GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT = {
"dryRun": false,
"auth": "my-token",
"pullRequest": `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${MERGED_SQUASHED_MR.iid}`,
"targetBranch": "prod",
"gitUser": "Me",
"gitEmail": "me@email.com",
"title": "New Title",
"body": "New Body",
"bodyPrefix": "New Body Prefix -",
"reviewers": [],
"assignees": ["user3", "user4"],
"inheritReviewers": false,
};
jest.mock("axios", () => {
return {
@ -20,15 +45,27 @@ describe("gitlab merge request config parser", () => {
const openPRUrl = `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${OPEN_MR.iid}`;
const notMergedPRUrl = `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${CLOSED_NOT_MERGED_MR.iid}`;
let parser: PullRequestConfigsParser;
let argsParser: GHAArgsParser;
let configParser: PullRequestConfigsParser;
beforeAll(() => {
// create a temporary file
createTestFile(GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME, JSON.stringify(GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT));
createTestFile(GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME, JSON.stringify(GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT));
GitClientFactory.reset();
GitClientFactory.getOrCreate(GitClientType.GITLAB, "whatever", "my.gitlab.host.com");
});
afterAll(() => {
// clean up all temporary files
removeTestFile(GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME);
removeTestFile(GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME);
});
beforeEach(() => {
parser = new PullRequestConfigsParser();
argsParser = new GHAArgsParser();
configParser = new PullRequestConfigsParser();
});
afterEach(() => {
@ -38,24 +75,24 @@ describe("gitlab merge request config parser", () => {
test("parse configs from merge request", async () => {
const args: Args = {
dryRun: false,
auth: "",
auth: undefined,
pullRequest: mergedPRUrl,
targetBranch: "prod",
gitUser: "GitLab",
gitUser: "Gitlab",
gitEmail: "noreply@gitlab.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "GitLab",
user: "Gitlab",
email: "noreply@gitlab.com"
});
expect(configs.auth).toEqual("");
expect(configs.auth).toEqual(undefined);
expect(configs.targetBranch).toEqual("prod");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.originalPullRequest).toEqual({
@ -84,7 +121,7 @@ describe("gitlab merge request config parser", () => {
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
});
expect(configs.backportPullRequest).toEqual({
author: "GitLab",
author: "Gitlab",
url: undefined,
htmlUrl: undefined,
title: "[prod] Update test.txt",
@ -113,21 +150,21 @@ describe("gitlab merge request config parser", () => {
pullRequest: mergedPRUrl,
targetBranch: "prod",
folder: "/tmp/test",
gitUser: "GitLab",
gitUser: "Gitlab",
gitEmail: "noreply@gitlab.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(true);
expect(configs.auth).toEqual("whatever");
expect(configs.targetBranch).toEqual("prod");
expect(configs.folder).toEqual("/tmp/test");
expect(configs.git).toEqual({
user: "GitLab",
user: "Gitlab",
email: "noreply@gitlab.com"
});
});
@ -138,20 +175,20 @@ describe("gitlab merge request config parser", () => {
auth: "whatever",
pullRequest: openPRUrl,
targetBranch: "prod",
gitUser: "GitLab",
gitUser: "Gitlab",
gitEmail: "noreply@gitlab.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(true);
expect(configs.auth).toEqual("whatever");
expect(configs.targetBranch).toEqual("prod");
expect(configs.git).toEqual({
user: "GitLab",
user: "Gitlab",
email: "noreply@gitlab.com"
});
expect(configs.originalPullRequest).toEqual({
@ -189,14 +226,14 @@ describe("gitlab merge request config parser", () => {
auth: "whatever",
pullRequest: notMergedPRUrl,
targetBranch: "prod",
gitUser: "GitLab",
gitUser: "Gitlab",
gitEmail: "noreply@gitlab.com",
reviewers: [],
assignees: [],
inheritReviewers: true,
};
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
expect(async () => await configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
});
test("override backport pr data inherting reviewers", async () => {
@ -215,7 +252,7 @@ describe("gitlab merge request config parser", () => {
inheritReviewers: true,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -288,7 +325,7 @@ describe("gitlab merge request config parser", () => {
inheritReviewers: true, // not taken into account
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -361,7 +398,7 @@ describe("gitlab merge request config parser", () => {
inheritReviewers: false,
};
const configs: Configs = await parser.parseAndValidate(args);
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
@ -417,4 +454,131 @@ describe("gitlab merge request config parser", () => {
bpBranchName: undefined,
});
});
test("using simple config file", async () => {
spyGetInput({
"config-file": GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME,
});
const args: Args = argsParser.parse();
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "Gitlab",
email: "noreply@gitlab.com"
});
expect(configs.auth).toEqual(undefined);
expect(configs.targetBranch).toEqual("prod");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.originalPullRequest).toEqual({
number: 1,
author: "superuser",
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
state: "merged",
merged: true,
mergedBy: "superuser",
title: "Update test.txt",
body: "This is the body",
reviewers: ["superuser1", "superuser2"],
assignees: ["superuser"],
targetRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
sourceRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
nCommits: 1,
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
});
expect(configs.backportPullRequest).toEqual({
author: "Gitlab",
url: undefined,
htmlUrl: undefined,
title: "[prod] Update test.txt",
body: "**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1\r\n\r\nThis is the body",
reviewers: ["superuser"],
assignees: [],
targetRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
sourceRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
bpBranchName: undefined,
});
});
test("using complex config file", async () => {
spyGetInput({
"config-file": GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT_PATHNAME,
});
const args: Args = argsParser.parse();
const configs: Configs = await configParser.parseAndValidate(args);
expect(configs.dryRun).toEqual(false);
expect(configs.git).toEqual({
user: "Me",
email: "me@email.com"
});
expect(configs.auth).toEqual("my-token");
expect(configs.targetBranch).toEqual("prod");
expect(configs.folder).toEqual(process.cwd() + "/bp");
expect(configs.originalPullRequest).toEqual({
number: 1,
author: "superuser",
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
state: "merged",
merged: true,
mergedBy: "superuser",
title: "Update test.txt",
body: "This is the body",
reviewers: ["superuser1", "superuser2"],
assignees: ["superuser"],
targetRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
sourceRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
nCommits: 1,
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
});
expect(configs.backportPullRequest).toEqual({
author: "Me",
url: undefined,
htmlUrl: undefined,
title: "New Title",
body: "New Body Prefix -New Body",
reviewers: [],
assignees: ["user3", "user4"],
targetRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
sourceRepo: {
owner: "superuser",
project: "backporting-example",
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
},
bpBranchName: undefined,
});
});
});