mirror of
https://code.forgejo.org/actions/git-backporting.git
synced 2025-02-22 18:45:44 -05:00
feat(issue-70): additional pr comments
This commit is contained in:
parent
10a46551ee
commit
bed7e29ddc
20 changed files with 424 additions and 16 deletions
|
@ -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 |
|
| 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 | --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" |
|
| 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 |
|
| 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).
|
> **NOTE**: `pull request` and `target branch` are *mandatory*, they must be provided as CLI options or as part of the configuration file (if used).
|
||||||
|
|
|
@ -67,6 +67,9 @@ inputs:
|
||||||
description: "Cherry-pick merge strategy option"
|
description: "Cherry-pick merge strategy option"
|
||||||
required: false
|
required: false
|
||||||
default: "theirs"
|
default: "theirs"
|
||||||
|
comments:
|
||||||
|
description: "Semicolon separated list of additional comments to be posted to the backported pull request"
|
||||||
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node16
|
using: node16
|
||||||
|
|
32
dist/cli/index.js
vendored
32
dist/cli/index.js
vendored
|
@ -63,6 +63,7 @@ class ArgsParser {
|
||||||
squash: this.getOrDefault(args.squash, true),
|
squash: this.getOrDefault(args.squash, true),
|
||||||
strategy: this.getOrDefault(args.strategy),
|
strategy: this.getOrDefault(args.strategy),
|
||||||
strategyOption: this.getOrDefault(args.strategyOption),
|
strategyOption: this.getOrDefault(args.strategyOption),
|
||||||
|
comments: this.getOrDefault(args.comments)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
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));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
/**
|
/**
|
||||||
* Parse the input configuation string as json object and
|
* Parse the input configuation string as json object and
|
||||||
|
@ -145,6 +146,12 @@ function getAsCommaSeparatedList(value) {
|
||||||
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
|
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
|
||||||
}
|
}
|
||||||
exports.getAsCommaSeparatedList = getAsCommaSeparatedList;
|
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) {
|
function getAsBooleanOrDefault(value) {
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
||||||
|
@ -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("--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 <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
|
||||||
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
|
.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");
|
.option("-cf, --config-file <config-file>", "configuration file containing all valid options, the json must match Args interface");
|
||||||
}
|
}
|
||||||
readArgs() {
|
readArgs() {
|
||||||
|
@ -223,6 +231,7 @@ class CLIArgsParser extends args_parser_1.default {
|
||||||
squash: opts.squash,
|
squash: opts.squash,
|
||||||
strategy: opts.strategy,
|
strategy: opts.strategy,
|
||||||
strategyOption: opts.strategyOption,
|
strategyOption: opts.strategyOption,
|
||||||
|
comments: opts.comments,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
@ -356,7 +365,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
assignees: [...new Set(args.assignees)],
|
assignees: [...new Set(args.assignees)],
|
||||||
labels: [...new Set(labels)],
|
labels: [...new Set(labels)],
|
||||||
comments: [], // TODO fix comments
|
comments: args.comments ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -721,6 +730,16 @@ class GitHubClient {
|
||||||
assignees: backport.assignees,
|
assignees: backport.assignees,
|
||||||
}).catch(error => this.logger.error(`Error setting assignees: ${error}`)));
|
}).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);
|
await Promise.all(promises);
|
||||||
return data.html_url;
|
return data.html_url;
|
||||||
}
|
}
|
||||||
|
@ -917,6 +936,15 @@ class GitLabClient {
|
||||||
labels: backport.labels.join(","),
|
labels: backport.labels.join(","),
|
||||||
}).catch(error => this.logger.warn("Failure trying to update labels. " + error)));
|
}).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
|
// reviewers
|
||||||
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
|
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
|
||||||
this.logger.debug("Retrieving user: " + r);
|
this.logger.debug("Retrieving user: " + r);
|
||||||
|
|
31
dist/gha/index.js
vendored
31
dist/gha/index.js
vendored
|
@ -63,6 +63,7 @@ class ArgsParser {
|
||||||
squash: this.getOrDefault(args.squash, true),
|
squash: this.getOrDefault(args.squash, true),
|
||||||
strategy: this.getOrDefault(args.strategy),
|
strategy: this.getOrDefault(args.strategy),
|
||||||
strategyOption: this.getOrDefault(args.strategyOption),
|
strategyOption: this.getOrDefault(args.strategyOption),
|
||||||
|
comments: this.getOrDefault(args.comments)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
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));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
/**
|
/**
|
||||||
* Parse the input configuation string as json object and
|
* Parse the input configuation string as json object and
|
||||||
|
@ -145,6 +146,12 @@ function getAsCommaSeparatedList(value) {
|
||||||
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
|
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : undefined;
|
||||||
}
|
}
|
||||||
exports.getAsCommaSeparatedList = getAsCommaSeparatedList;
|
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) {
|
function getAsBooleanOrDefault(value) {
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
||||||
|
@ -194,6 +201,7 @@ class GHAArgsParser extends args_parser_1.default {
|
||||||
squash: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-squash")),
|
squash: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-squash")),
|
||||||
strategy: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy")),
|
strategy: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy")),
|
||||||
strategyOption: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("strategy-option")),
|
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;
|
return args;
|
||||||
|
@ -327,7 +335,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
assignees: [...new Set(args.assignees)],
|
assignees: [...new Set(args.assignees)],
|
||||||
labels: [...new Set(labels)],
|
labels: [...new Set(labels)],
|
||||||
comments: [], // TODO fix comments
|
comments: args.comments ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -692,6 +700,16 @@ class GitHubClient {
|
||||||
assignees: backport.assignees,
|
assignees: backport.assignees,
|
||||||
}).catch(error => this.logger.error(`Error setting assignees: ${error}`)));
|
}).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);
|
await Promise.all(promises);
|
||||||
return data.html_url;
|
return data.html_url;
|
||||||
}
|
}
|
||||||
|
@ -888,6 +906,15 @@ class GitLabClient {
|
||||||
labels: backport.labels.join(","),
|
labels: backport.labels.join(","),
|
||||||
}).catch(error => this.logger.warn("Failure trying to update labels. " + error)));
|
}).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
|
// reviewers
|
||||||
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
|
const reviewerIds = await Promise.all(backport.reviewers.map(async (r) => {
|
||||||
this.logger.debug("Retrieving user: " + r);
|
this.logger.debug("Retrieving user: " + r);
|
||||||
|
|
|
@ -41,6 +41,7 @@ export default abstract class ArgsParser {
|
||||||
squash: this.getOrDefault(args.squash, true),
|
squash: this.getOrDefault(args.squash, true),
|
||||||
strategy: this.getOrDefault(args.strategy),
|
strategy: this.getOrDefault(args.strategy),
|
||||||
strategyOption: this.getOrDefault(args.strategyOption),
|
strategyOption: this.getOrDefault(args.strategyOption),
|
||||||
|
comments: this.getOrDefault(args.comments)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,6 +44,12 @@ export function getAsCommaSeparatedList(value: string): string[] | undefined {
|
||||||
return trimmed !== "" ? trimmed.split(",").map(v => v.trim()) : 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 {
|
export function getAsBooleanOrDefault(value: string): boolean | undefined {
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
||||||
|
|
|
@ -21,4 +21,5 @@ export interface Args {
|
||||||
squash?: boolean, // if false use squashed/merged commit otherwise backport all commits as part of the pr
|
squash?: boolean, // if false use squashed/merged commit otherwise backport all commits as part of the pr
|
||||||
strategy?: string, // cherry-pick merge strategy
|
strategy?: string, // cherry-pick merge strategy
|
||||||
strategyOption?: string, // cherry-pick merge strategy option
|
strategyOption?: string, // cherry-pick merge strategy option
|
||||||
|
comments?: string[], // additional comments to be posted
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ import ArgsParser from "@bp/service/args/args-parser";
|
||||||
import { Args } from "@bp/service/args/args.types";
|
import { Args } from "@bp/service/args/args.types";
|
||||||
import { Command } from "commander";
|
import { Command } from "commander";
|
||||||
import { name, version, description } from "@bp/../package.json";
|
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 {
|
export default class CLIArgsParser extends ArgsParser {
|
||||||
|
|
||||||
|
@ -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("--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 <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
|
||||||
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
|
.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");
|
.option("-cf, --config-file <config-file>", "configuration file containing all valid options, the json must match Args interface");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ export default class CLIArgsParser extends ArgsParser {
|
||||||
squash: opts.squash,
|
squash: opts.squash,
|
||||||
strategy: opts.strategy,
|
strategy: opts.strategy,
|
||||||
strategyOption: opts.strategyOption,
|
strategyOption: opts.strategyOption,
|
||||||
|
comments: opts.comments,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import ArgsParser from "@bp/service/args/args-parser";
|
import ArgsParser from "@bp/service/args/args-parser";
|
||||||
import { Args } from "@bp/service/args/args.types";
|
import { Args } from "@bp/service/args/args.types";
|
||||||
import { getInput } from "@actions/core";
|
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 {
|
export default class GHAArgsParser extends ArgsParser {
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ export default class GHAArgsParser extends ArgsParser {
|
||||||
squash: !getAsBooleanOrDefault(getInput("no-squash")),
|
squash: !getAsBooleanOrDefault(getInput("no-squash")),
|
||||||
strategy: getOrUndefined(getInput("strategy")),
|
strategy: getOrUndefined(getInput("strategy")),
|
||||||
strategyOption: getOrUndefined(getInput("strategy-option")),
|
strategyOption: getOrUndefined(getInput("strategy-option")),
|
||||||
|
comments: getAsSemicolonSeparatedList(getInput("comments")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
assignees: [...new Set(args.assignees)],
|
assignees: [...new Set(args.assignees)],
|
||||||
labels: [...new Set(labels)],
|
labels: [...new Set(labels)],
|
||||||
comments: [], // TODO fix comments
|
comments: args.comments ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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}`))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
return data.html_url;
|
return data.html_url;
|
||||||
|
|
|
@ -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))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// reviewers
|
// reviewers
|
||||||
const reviewerIds = await Promise.all(backport.reviewers.map(async r => {
|
const reviewerIds = await Promise.all(backport.reviewers.map(async r => {
|
||||||
this.logger.debug("Retrieving user: " + r);
|
this.logger.debug("Retrieving user: " + r);
|
||||||
|
|
|
@ -402,4 +402,35 @@ describe("cli args parser", () => {
|
||||||
expect(args.strategy).toEqual("ort");
|
expect(args.strategy).toEqual("ort");
|
||||||
expect(args.strategyOption).toEqual("ours");
|
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"]);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -236,4 +236,30 @@ describe("gha args parser", () => {
|
||||||
expect(args.strategy).toEqual("ort");
|
expect(args.strategy).toEqual("ort");
|
||||||
expect(args.strategyOption).toEqual("ours");
|
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"]);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -725,4 +725,79 @@ describe("github pull request config parser", () => {
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("override backport pr with additional comments", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
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: ["First comment", "Second comment"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "Me",
|
||||||
|
email: "me@email.com"
|
||||||
|
});
|
||||||
|
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"],
|
||||||
|
assignees: [],
|
||||||
|
labels: ["original-label"],
|
||||||
|
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({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-prod-28f63db",
|
||||||
|
base: "prod",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix -New Body",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
labels: [],
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -723,4 +723,78 @@ describe("gitlab merge request config parser", () => {
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("override backport pr with additional comments", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
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: ["First comment", "Second comment"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledWith("superuser", "backporting-example", 1, true);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "Me",
|
||||||
|
email: "me@email.com"
|
||||||
|
});
|
||||||
|
expect(configs.auth).toEqual("");
|
||||||
|
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"],
|
||||||
|
labels: ["gitlab-original-label"],
|
||||||
|
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({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-prod-ebb1eca",
|
||||||
|
base: "prod",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix -New Body",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
labels: [],
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -305,7 +305,7 @@ describe("github service", () => {
|
||||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + SECOND_NEW_GITLAB_MR_ID);
|
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + SECOND_NEW_GITLAB_MR_ID);
|
||||||
|
|
||||||
// check axios invocation
|
// check axios invocation
|
||||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
expect(axiosInstanceSpy.post).toBeCalledTimes(3); // also comments
|
||||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||||
source_branch: "bp-branch-2",
|
source_branch: "bp-branch-2",
|
||||||
target_branch: "old/branch",
|
target_branch: "old/branch",
|
||||||
|
@ -315,10 +315,12 @@ describe("github service", () => {
|
||||||
assignee_ids: [],
|
assignee_ids: [],
|
||||||
}));
|
}));
|
||||||
expect(axiosInstanceSpy.get).toBeCalledTimes(0);
|
expect(axiosInstanceSpy.get).toBeCalledTimes(0);
|
||||||
// FIXME
|
|
||||||
// expect(axiosInstanceSpy.put).toBeCalledTimes(1); // just comments
|
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + SECOND_NEW_GITLAB_MR_ID + "/notes", {
|
||||||
// expect(axiosInstanceSpy.put).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + SECOND_NEW_GITLAB_MR_ID, {
|
body: "this is first comment",
|
||||||
// labels: "label1,label2",
|
});
|
||||||
// });
|
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + SECOND_NEW_GITLAB_MR_ID + "/notes", {
|
||||||
|
body: "this is second comment",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -793,4 +793,51 @@ describe("cli runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("additional pr comments", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/8632",
|
||||||
|
"--comments",
|
||||||
|
"first comment; second comment"
|
||||||
|
]);
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
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-28f63db");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-28f63db",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] PR Title",
|
||||||
|
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/8632"),
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: ["first comment", "second comment"],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -554,4 +554,49 @@ describe("gha runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("additional pr comments", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://github.com/owner/reponame/pull/2368",
|
||||||
|
"comments": "first comment; second comment",
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
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-28f63db");
|
||||||
|
|
||||||
|
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", undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-28f63db",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] PR Title",
|
||||||
|
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/2368"),
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: ["first comment", "second comment"],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -34,18 +34,24 @@ export const getAxiosMocked = (url: string) => {
|
||||||
|
|
||||||
export const NEW_GITLAB_MR_ID = 999;
|
export const NEW_GITLAB_MR_ID = 999;
|
||||||
export const SECOND_NEW_GITLAB_MR_ID = 1000;
|
export const SECOND_NEW_GITLAB_MR_ID = 1000;
|
||||||
export const postAxiosMocked = (_url: string, data?: {source_branch: string,}) => {
|
export const postAxiosMocked = async (url: string, data?: {source_branch: string,}) => {
|
||||||
let responseData = undefined;
|
let responseData = undefined;
|
||||||
|
|
||||||
// gitlab
|
// gitlab
|
||||||
|
|
||||||
if (data?.source_branch === "bp-branch") {
|
if (url.includes("notes")) {
|
||||||
|
// creating comments
|
||||||
|
responseData = {
|
||||||
|
// we do not need the whole response
|
||||||
|
iid: NEW_GITLAB_MR_ID,
|
||||||
|
};
|
||||||
|
} else if (data?.source_branch === "bp-branch") {
|
||||||
responseData = {
|
responseData = {
|
||||||
// we do not need the whole response
|
// we do not need the whole response
|
||||||
iid: NEW_GITLAB_MR_ID,
|
iid: NEW_GITLAB_MR_ID,
|
||||||
web_url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID
|
web_url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID
|
||||||
};
|
};
|
||||||
} if (data?.source_branch === "bp-branch-2") {
|
} else if (data?.source_branch === "bp-branch-2") {
|
||||||
responseData = {
|
responseData = {
|
||||||
// we do not need the whole response
|
// we do not need the whole response
|
||||||
iid: SECOND_NEW_GITLAB_MR_ID,
|
iid: SECOND_NEW_GITLAB_MR_ID,
|
||||||
|
@ -169,6 +175,13 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
data: {}
|
data: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mock.rest.issues
|
||||||
|
.createComment()
|
||||||
|
.reply({
|
||||||
|
status: 201,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
// invalid requests
|
// invalid requests
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
.get({
|
.get({
|
||||||
|
|
Loading…
Add table
Reference in a new issue