Skip to content

Commit

Permalink
feat(issue-70): additional pr comments
Browse files Browse the repository at this point in the history
  • Loading branch information
lampajr committed Jul 27, 2023
1 parent 10a4655 commit bed7e29
Show file tree
Hide file tree
Showing 20 changed files with 424 additions and 16 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ This tool comes with some inputs that allow users to override the default behavi
| No squash | --no-squash | N | If provided the backporting will try to backport all pull request commits without squashing | false |
| Strategy | --strategy | N | Cherry pick merging strategy, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "recursive" |
| Strategy Option | --strategy-option | N | Cherry pick merging strategy option, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "theirs" |
| Additional comments | --comments | N | Semicolon separated list of additional comments to be posted to the backported pull request | [] |
| Dry Run | -d, --dry-run | N | If enabled the tool does not push nor create anything remotely, use this to skip PR creation | false |

> **NOTE**: `pull request` and `target branch` are *mandatory*, they must be provided as CLI options or as part of the configuration file (if used).
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ inputs:
description: "Cherry-pick merge strategy option"
required: false
default: "theirs"
comments:
description: "Semicolon separated list of additional comments to be posted to the backported pull request"
required: false

runs:
using: node16
Expand Down
32 changes: 30 additions & 2 deletions dist/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ArgsParser {
squash: this.getOrDefault(args.squash, true),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
comments: this.getOrDefault(args.comments)
};
}
}
Expand Down Expand Up @@ -100,7 +101,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getAsBooleanOrDefault = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
const fs = __importStar(__nccwpck_require__(7147));
/**
* Parse the input configuation string as json object and
Expand Down Expand Up @@ -145,6 +146,12 @@ function getAsCommaSeparatedList(value) {
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
}
exports.getAsCommaSeparatedList = getAsCommaSeparatedList;
function getAsSemicolonSeparatedList(value) {
// trim the value
const trimmed = value.trim();
return trimmed !== "" ? trimmed.split(";").map(v => v.trim()) : undefined;
}
exports.getAsSemicolonSeparatedList = getAsSemicolonSeparatedList;
function getAsBooleanOrDefault(value) {
const trimmed = value.trim();
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
Expand Down Expand Up @@ -191,6 +198,7 @@ class CLIArgsParser extends args_parser_1.default {
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
.option("--comments <comments>", "semicolon separated list of additional comments to be posted to the backported pull request", args_utils_1.getAsSemicolonSeparatedList)
.option("-cf, --config-file <config-file>", "configuration file containing all valid options, the json must match Args interface");
}
readArgs() {
Expand Down Expand Up @@ -223,6 +231,7 @@ class CLIArgsParser extends args_parser_1.default {
squash: opts.squash,
strategy: opts.strategy,
strategyOption: opts.strategyOption,
comments: opts.comments,
};
}
return args;
Expand Down Expand Up @@ -356,7 +365,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
reviewers: [...new Set(reviewers)],
assignees: [...new Set(args.assignees)],
labels: [...new Set(labels)],
comments: [], // TODO fix comments
comments: args.comments ?? [],
};
}
}
Expand Down Expand Up @@ -721,6 +730,16 @@ class GitHubClient {
assignees: backport.assignees,
}).catch(error => this.logger.error(`Error setting assignees: ${error}`)));
}
if (backport.comments.length > 0) {
backport.comments.forEach(c => {
promises.push(this.octokit.issues.createComment({
owner: backport.owner,
repo: backport.repo,
issue_number: data.number,
body: c,
}).catch(error => this.logger.error(`Error posting comment: ${error}`)));
});
}
await Promise.all(promises);
return data.html_url;
}
Expand Down Expand Up @@ -917,6 +936,15 @@ class GitLabClient {
labels: backport.labels.join(","),
}).catch(error => this.logger.warn("Failure trying to update labels. " + error)));
}
// comments
if (backport.comments.length > 0) {
this.logger.info("Posting comments: " + backport.comments);
backport.comments.forEach(c => {
promises.push(this.client.post(`/projects/${projectId}/merge_requests/${mr.iid}/notes`, {
body: c,
}).catch(error => this.logger.warn("Failure trying to post comment. " + error)));
});
}
// reviewers
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
this.logger.debug("Retrieving user: " + r);
Expand Down
31 changes: 29 additions & 2 deletions dist/gha/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ArgsParser {
squash: this.getOrDefault(args.squash, true),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
comments: this.getOrDefault(args.comments)
};
}
}
Expand Down Expand Up @@ -100,7 +101,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getAsBooleanOrDefault = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
exports.getAsBooleanOrDefault = exports.getAsSemicolonSeparatedList = exports.getAsCommaSeparatedList = exports.getAsCleanedCommaSeparatedList = exports.getOrUndefined = exports.readConfigFile = exports.parseArgs = void 0;
const fs = __importStar(__nccwpck_require__(7147));
/**
* Parse the input configuation string as json object and
Expand Down Expand Up @@ -145,6 +146,12 @@ function getAsCommaSeparatedList(value) {
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
}
exports.getAsCommaSeparatedList = getAsCommaSeparatedList;
function getAsSemicolonSeparatedList(value) {
// trim the value
const trimmed = value.trim();
return trimmed !== "" ? trimmed.split(";").map(v => v.trim()) : undefined;
}
exports.getAsSemicolonSeparatedList = getAsSemicolonSeparatedList;
function getAsBooleanOrDefault(value) {
const trimmed = value.trim();
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
Expand Down Expand Up @@ -194,6 +201,7 @@ class GHAArgsParser extends args_parser_1.default {
squash: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-squash")),
strategy: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy")),
strategyOption: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy-option")),
comments: (0, args_utils_1.getAsSemicolonSeparatedList)((0, core_1.getInput)("comments")),
};
}
return args;
Expand Down Expand Up @@ -327,7 +335,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
reviewers: [...new Set(reviewers)],
assignees: [...new Set(args.assignees)],
labels: [...new Set(labels)],
comments: [], // TODO fix comments
comments: args.comments ?? [],
};
}
}
Expand Down Expand Up @@ -692,6 +700,16 @@ class GitHubClient {
assignees: backport.assignees,
}).catch(error => this.logger.error(`Error setting assignees: ${error}`)));
}
if (backport.comments.length > 0) {
backport.comments.forEach(c => {
promises.push(this.octokit.issues.createComment({
owner: backport.owner,
repo: backport.repo,
issue_number: data.number,
body: c,
}).catch(error => this.logger.error(`Error posting comment: ${error}`)));
});
}
await Promise.all(promises);
return data.html_url;
}
Expand Down Expand Up @@ -888,6 +906,15 @@ class GitLabClient {
labels: backport.labels.join(","),
}).catch(error => this.logger.warn("Failure trying to update labels. " + error)));
}
// comments
if (backport.comments.length > 0) {
this.logger.info("Posting comments: " + backport.comments);
backport.comments.forEach(c => {
promises.push(this.client.post(`/projects/${projectId}/merge_requests/${mr.iid}/notes`, {
body: c,
}).catch(error => this.logger.warn("Failure trying to post comment. " + error)));
});
}
// reviewers
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
this.logger.debug("Retrieving user: " + r);
Expand Down
1 change: 1 addition & 0 deletions src/service/args/args-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default abstract class ArgsParser {
squash: this.getOrDefault(args.squash, true),
strategy: this.getOrDefault(args.strategy),
strategyOption: this.getOrDefault(args.strategyOption),
comments: this.getOrDefault(args.comments)
};
}
}
6 changes: 6 additions & 0 deletions src/service/args/args-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export function getAsCommaSeparatedList(value: string): string[] | undefined {
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
}

export function getAsSemicolonSeparatedList(value: string): string[] | undefined {
// trim the value
const trimmed: string = value.trim();
return trimmed !== "" ? trimmed.split(";").map(v => v.trim()) : undefined;
}

export function getAsBooleanOrDefault(value: string): boolean | undefined {
const trimmed = value.trim();
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
Expand Down
1 change: 1 addition & 0 deletions src/service/args/args.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ export interface Args {
squash?: boolean, // if false use squashed/merged commit otherwise backport all commits as part of the pr
strategy?: string, // cherry-pick merge strategy
strategyOption?: string, // cherry-pick merge strategy option
comments?: string[], // additional comments to be posted
}
4 changes: 3 additions & 1 deletion src/service/args/cli/cli-args-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ArgsParser from "@bp/service/args/args-parser";
import { Args } from "@bp/service/args/args.types";
import { Command } from "commander";
import { name, version, description } from "@bp/../package.json";
import { getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, readConfigFile } from "@bp/service/args/args-utils";
import { getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, readConfigFile } from "@bp/service/args/args-utils";

export default class CLIArgsParser extends ArgsParser {

Expand All @@ -29,6 +29,7 @@ export default class CLIArgsParser extends ArgsParser {
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
.option("--comments <comments>", "semicolon separated list of additional comments to be posted to the backported pull request", getAsSemicolonSeparatedList)
.option("-cf, --config-file <config-file>", "configuration file containing all valid options, the json must match Args interface");
}

Expand Down Expand Up @@ -62,6 +63,7 @@ export default class CLIArgsParser extends ArgsParser {
squash: opts.squash,
strategy: opts.strategy,
strategyOption: opts.strategyOption,
comments: opts.comments,
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/service/args/gha/gha-args-parser.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ArgsParser from "@bp/service/args/args-parser";
import { Args } from "@bp/service/args/args.types";
import { getInput } from "@actions/core";
import { getAsBooleanOrDefault, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";
import { getAsBooleanOrDefault, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";

export default class GHAArgsParser extends ArgsParser {

Expand Down Expand Up @@ -32,6 +32,7 @@ export default class GHAArgsParser extends ArgsParser {
squash: !getAsBooleanOrDefault(getInput("no-squash")),
strategy: getOrUndefined(getInput("strategy")),
strategyOption: getOrUndefined(getInput("strategy-option")),
comments: getAsSemicolonSeparatedList(getInput("comments")),
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/service/configs/pullrequest/pr-configs-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default class PullRequestConfigsParser extends ConfigsParser {
reviewers: [...new Set(reviewers)],
assignees: [...new Set(args.assignees)],
labels: [...new Set(labels)],
comments: [], // TODO fix comments
comments: args.comments ?? [],
};
}
}
13 changes: 13 additions & 0 deletions src/service/git/github/github-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ export default class GitHubClient implements GitClient {
);
}

if (backport.comments.length > 0) {
backport.comments.forEach(c => {
promises.push(
this.octokit.issues.createComment({
owner: backport.owner,
repo: backport.repo,
issue_number: (data as PullRequest).number,
body: c,
}).catch(error => this.logger.error(`Error posting comment: ${error}`))

Check warning on line 128 in src/service/git/github/github-client.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 128 in src/service/git/github/github-client.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
);
});
}

await Promise.all(promises);

return data.html_url;
Expand Down
12 changes: 12 additions & 0 deletions src/service/git/gitlab/gitlab-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ export default class GitLabClient implements GitClient {
);
}

// comments
if (backport.comments.length > 0) {
this.logger.info("Posting comments: " + backport.comments);
backport.comments.forEach(c => {
promises.push(
this.client.post(`/projects/${projectId}/merge_requests/${mr.iid}/notes`, {
body: c,
}).catch(error => this.logger.warn("Failure trying to post comment. " + error))

Check warning on line 106 in src/service/git/gitlab/gitlab-client.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 106 in src/service/git/gitlab/gitlab-client.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
);
});
}

// reviewers
const reviewerIds = await Promise.all(backport.reviewers.map(async r => {
this.logger.debug("Retrieving user: " + r);
Expand Down
31 changes: 31 additions & 0 deletions test/service/args/cli/cli-args-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,4 +402,35 @@ describe("cli args parser", () => {
expect(args.strategy).toEqual("ort");
expect(args.strategyOption).toEqual("ours");
});

test("additional pr comments", () => {
addProcessArgs([
"--target-branch",
"target",
"--pull-request",
"https://localhost/whatever/pulls/1",
"--comments",
"first comment;second comment",
]);

const args: Args = parser.parse();
expect(args.dryRun).toEqual(false);
expect(args.auth).toEqual(undefined);
expect(args.gitUser).toEqual(undefined);
expect(args.gitEmail).toEqual(undefined);
expect(args.folder).toEqual(undefined);
expect(args.targetBranch).toEqual("target");
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
expect(args.title).toEqual(undefined);
expect(args.body).toEqual(undefined);
expect(args.bodyPrefix).toEqual(undefined);
expect(args.bpBranchName).toEqual(undefined);
expect(args.reviewers).toEqual([]);
expect(args.assignees).toEqual([]);
expect(args.inheritReviewers).toEqual(true);
expect(args.labels).toEqual([]);
expect(args.inheritLabels).toEqual(false);
expect(args.squash).toEqual(true);
expectArrayEqual(args.comments!,["first comment", "second comment"]);
});
});
26 changes: 26 additions & 0 deletions test/service/args/gha/gha-args-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,30 @@ describe("gha args parser", () => {
expect(args.strategy).toEqual("ort");
expect(args.strategyOption).toEqual("ours");
});

test("additional pr comments", () => {
spyGetInput({
"target-branch": "target",
"pull-request": "https://localhost/whatever/pulls/1",
"comments": "first comment;second comment",
});

const args: Args = parser.parse();
expect(args.dryRun).toEqual(false);
expect(args.auth).toEqual(undefined);
expect(args.gitUser).toEqual(undefined);
expect(args.gitEmail).toEqual(undefined);
expect(args.folder).toEqual(undefined);
expect(args.targetBranch).toEqual("target");
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
expect(args.title).toEqual(undefined);
expect(args.body).toEqual(undefined);
expect(args.reviewers).toEqual([]);
expect(args.assignees).toEqual([]);
expect(args.inheritReviewers).toEqual(true);
expect(args.labels).toEqual([]);
expect(args.inheritLabels).toEqual(false);
expect(args.squash).toEqual(true);
expectArrayEqual(args.comments!,["first comment", "second comment"]);
});
});

0 comments on commit bed7e29

Please sign in to comment.