mirror of
https://code.forgejo.org/actions/git-backporting
synced 2025-03-14 22:27:02 +01:00
feat: auto-detect the value of the no-squash option (#118)
The auto-no-squash option is added to: * backport all the commits when the pull/merge request has been merged * backport the squashed commit otherwise It is equivalent to dynamically adjust the value of the no-squash option, depending on the context. The no-squash option is kept for backward compatibility for a single use case: backporting the merged commit instead of backporting the commits of the pull/merge request request. Detecting if a pull/merge request was squashed or not depends on the underlying forge: * Forgejo / GitHub: use the API to count the number of parents * GitLab: if the squash_commit_sha is set, the merge request was squashed If the pull/merge request is open, always backport all the commits it contains. Fixes: https://github.com/kiegroup/git-backporting/issues/113 Co-authored-by: Andrea Lamparelli <a.lamparelli95@gmail.com>
This commit is contained in:
parent
fc5dba6703
commit
6042bcc40b
23 changed files with 324 additions and 54 deletions
11
README.md
11
README.md
|
@ -70,7 +70,13 @@ It works in this way: given the provided `pull/merge request` it infers the serv
|
|||
|
||||
After that it clones the corresponding git repository, check out in the provided `target branch` and create a new branch from that (name automatically generated if not provided as option).
|
||||
|
||||
By default the tool will try to cherry-pick the single squashed/merged commit into the newly created branch (please consider using `--no-squash` option if you want to cherry-pick all commits belonging to the provided pull request).
|
||||
By default the tool will try to cherry-pick the single squashed/merged commit into the newly created branch. The `--no-squash` and `--auto-no-squash` options control this behavior according the following table.
|
||||
|
||||
| No squash | Auto no squash |Behavior|
|
||||
|---|---|---|
|
||||
| unset/false | unset/false | cherry-pick a single commit, squashed or merged |
|
||||
| set/true | unset/false | cherry-pick all commits found in the the original pull/merge request|
|
||||
| (ignored) | set/true | cherry-pick all commits if the original pull/merge request was merged, a single commit if it was squashed |
|
||||
|
||||
Based on the original pull request, creates a new one containing the backporting to the target branch. Note that most of these information can be overridden with appropriate CLI options or GHA inputs.
|
||||
|
||||
|
@ -121,7 +127,8 @@ This tool comes with some inputs that allow users to override the default behavi
|
|||
| Backport Branch Names | --bp-branch-name | N | Comma separated lists of the backporting pull request branch names, if they exceeds 250 chars they will be truncated | bp-{target-branch}-{sha1}...{shaN} |
|
||||
| Labels | --labels | N | Provide custom labels to be added to the backporting pull request | [] |
|
||||
| Inherit labels | --inherit-labels | N | If enabled inherit lables from the original pull request | false |
|
||||
| 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 | Backport all commits found in the pull request. The default behavior is to only backport the first commit that was merged in the base branch. | |
|
||||
| Auto no squash | --auto-no-squash | N | If the pull request was merged or is open, backport all commits. If the pull request commits were squashed, backport the squashed commit. | |
|
||||
| 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" |
|
||||
| Cherry-pick Options | --cherry-pick-options | N | Additional cherry-pick options, see [git-cherry-pick](https://git-scm.com/docs/git-cherry-pick) doc for all possible values | "theirs" |
|
||||
|
|
10
action.yml
10
action.yml
|
@ -85,10 +85,14 @@ inputs:
|
|||
default: "false"
|
||||
no-squash:
|
||||
description: >
|
||||
If set to true the tool will backport all commits as part of the pull request
|
||||
instead of the suqashed one
|
||||
Backport all commits found in the pull request.
|
||||
The default behavior is to only backport the first commit that was merged in the base branch.
|
||||
required: false
|
||||
auto-no-squash:
|
||||
description: >
|
||||
If the pull request was merged or is open, backport all commits.
|
||||
If the pull request commits were squashed, backport the squashed commit.
|
||||
required: false
|
||||
default: "false"
|
||||
strategy:
|
||||
description: Cherry-pick merge strategy
|
||||
required: false
|
||||
|
|
68
dist/cli/index.js
vendored
68
dist/cli/index.js
vendored
|
@ -66,6 +66,7 @@ class ArgsParser {
|
|||
labels: this.getOrDefault(args.labels, []),
|
||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||
squash: this.getOrDefault(args.squash, true),
|
||||
autoNoSquash: this.getOrDefault(args.autoNoSquash, false),
|
||||
strategy: this.getOrDefault(args.strategy),
|
||||
strategyOption: this.getOrDefault(args.strategyOption),
|
||||
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
|
||||
|
@ -203,7 +204,8 @@ class CLIArgsParser extends args_parser_1.default {
|
|||
.option("--no-inherit-reviewers", "if provided and reviewers option is empty then inherit them from original pull request")
|
||||
.option("--labels <labels>", "comma separated list of labels to be assigned to the backported pull request", args_utils_1.getAsCommaSeparatedList)
|
||||
.option("--inherit-labels", "if true the backported pull request will inherit labels from the original one")
|
||||
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
|
||||
.option("--no-squash", "Backport all commits found in the pull request. The default behavior is to only backport the first commit that was merged in the base branch")
|
||||
.option("--auto-no-squash", "If the pull request was merged or is open, backport all commits. If the pull request commits were squashed, backport the squashed commit.")
|
||||
.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("--cherry-pick-options <options>", "additional cherry-pick options")
|
||||
|
@ -240,6 +242,7 @@ class CLIArgsParser extends args_parser_1.default {
|
|||
labels: opts.labels,
|
||||
inheritLabels: opts.inheritLabels,
|
||||
squash: opts.squash,
|
||||
autoNoSquash: opts.autoNoSquash,
|
||||
strategy: opts.strategy,
|
||||
strategyOption: opts.strategyOption,
|
||||
cherryPickOptions: opts.cherryPickOptions,
|
||||
|
@ -332,6 +335,9 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
|||
}
|
||||
async parse(args) {
|
||||
let pr;
|
||||
if (args.autoNoSquash) {
|
||||
args.squash = undefined;
|
||||
}
|
||||
try {
|
||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash);
|
||||
}
|
||||
|
@ -661,12 +667,16 @@ GitClientFactory.logger = logger_service_factory_1.default.getLogger();
|
|||
/***/ }),
|
||||
|
||||
/***/ 9080:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getEnv = exports.getGitTokenFromEnv = exports.inferGitApiUrl = exports.inferGitClient = void 0;
|
||||
exports.getEnv = exports.getGitTokenFromEnv = exports.inferSquash = exports.inferGitApiUrl = exports.inferGitClient = void 0;
|
||||
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const configs_types_1 = __nccwpck_require__(4753);
|
||||
const PUBLIC_GITHUB_URL = "https://github.com";
|
||||
|
@ -706,6 +716,30 @@ const inferGitApiUrl = (prUrl, apiVersion = "v4") => {
|
|||
return `${baseUrl}/api/${apiVersion}`;
|
||||
};
|
||||
exports.inferGitApiUrl = inferGitApiUrl;
|
||||
/**
|
||||
* Infer the value of the squash option
|
||||
* @param open true if the pull/merge request is still open
|
||||
* @param squash_commit undefined if the pull/merge request was merged, the sha of the squashed commit if it was squashed
|
||||
* @returns true if a single commit must be cherry-picked, false if all merged commits must be cherry-picked
|
||||
*/
|
||||
const inferSquash = (open, squash_commit) => {
|
||||
const logger = logger_service_factory_1.default.getLogger();
|
||||
if (open) {
|
||||
logger.debug("cherry-pick all commits because they have not been merged (or squashed) in the base branch yet");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (squash_commit !== undefined) {
|
||||
logger.debug(`cherry-pick the squashed commit ${squash_commit}`);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.debug("cherry-pick the merged commit(s)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.inferSquash = inferSquash;
|
||||
/**
|
||||
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
|
||||
* All specific git env variable have precedence and override the default one.
|
||||
|
@ -781,6 +815,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const git_util_1 = __nccwpck_require__(9080);
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
|
||||
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
|
||||
|
@ -803,13 +838,28 @@ class GitHubClient {
|
|||
getDefaultGitEmail() {
|
||||
return "noreply@github.com";
|
||||
}
|
||||
async getPullRequest(owner, repo, prNumber, squash = true) {
|
||||
async getPullRequest(owner, repo, prNumber, squash) {
|
||||
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
|
||||
const { data } = await this.octokit.rest.pulls.get({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: prNumber,
|
||||
});
|
||||
if (squash === undefined) {
|
||||
let commit_sha = undefined;
|
||||
const open = data.state == "open";
|
||||
if (!open) {
|
||||
const commit = await this.octokit.rest.git.getCommit({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
commit_sha: data.merge_commit_sha,
|
||||
});
|
||||
if (commit.data.parents.length === 1) {
|
||||
commit_sha = data.merge_commit_sha;
|
||||
}
|
||||
}
|
||||
squash = (0, git_util_1.inferSquash)(open, commit_sha);
|
||||
}
|
||||
const commits = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -827,7 +877,7 @@ class GitHubClient {
|
|||
}
|
||||
return this.mapper.mapPullRequest(data, commits);
|
||||
}
|
||||
async getPullRequestFromUrl(prUrl, squash = true) {
|
||||
async getPullRequestFromUrl(prUrl, squash) {
|
||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||
return this.getPullRequest(owner, project, id, squash);
|
||||
}
|
||||
|
@ -1006,6 +1056,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const git_util_1 = __nccwpck_require__(9080);
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
|
||||
const gitlab_mapper_1 = __importDefault(__nccwpck_require__(2675));
|
||||
|
@ -1038,9 +1089,12 @@ class GitLabClient {
|
|||
}
|
||||
// READ
|
||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||
async getPullRequest(namespace, repo, mrNumber, squash = true) {
|
||||
async getPullRequest(namespace, repo, mrNumber, squash) {
|
||||
const projectId = this.getProjectId(namespace, repo);
|
||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||
if (squash === undefined) {
|
||||
squash = (0, git_util_1.inferSquash)(data.state == "opened", data.squash_commit_sha);
|
||||
}
|
||||
const commits = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -1055,7 +1109,7 @@ class GitLabClient {
|
|||
}
|
||||
return this.mapper.mapPullRequest(data, commits);
|
||||
}
|
||||
getPullRequestFromUrl(mrUrl, squash = true) {
|
||||
getPullRequestFromUrl(mrUrl, squash) {
|
||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||
return this.getPullRequest(namespace, project, id, squash);
|
||||
}
|
||||
|
|
65
dist/gha/index.js
vendored
65
dist/gha/index.js
vendored
|
@ -66,6 +66,7 @@ class ArgsParser {
|
|||
labels: this.getOrDefault(args.labels, []),
|
||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||
squash: this.getOrDefault(args.squash, true),
|
||||
autoNoSquash: this.getOrDefault(args.autoNoSquash, false),
|
||||
strategy: this.getOrDefault(args.strategy),
|
||||
strategyOption: this.getOrDefault(args.strategyOption),
|
||||
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
|
||||
|
@ -207,6 +208,7 @@ class GHAArgsParser extends args_parser_1.default {
|
|||
labels: (0, args_utils_1.getAsCommaSeparatedList)((0, core_1.getInput)("labels")),
|
||||
inheritLabels: (0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("inherit-labels")),
|
||||
squash: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-squash")),
|
||||
autoNoSquash: (0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("auto-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")),
|
||||
cherryPickOptions: (0, args_utils_1.getOrUndefined)((0, core_1.getInput)("cherry-pick-options")),
|
||||
|
@ -299,6 +301,9 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
|||
}
|
||||
async parse(args) {
|
||||
let pr;
|
||||
if (args.autoNoSquash) {
|
||||
args.squash = undefined;
|
||||
}
|
||||
try {
|
||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash);
|
||||
}
|
||||
|
@ -628,12 +633,16 @@ GitClientFactory.logger = logger_service_factory_1.default.getLogger();
|
|||
/***/ }),
|
||||
|
||||
/***/ 9080:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getEnv = exports.getGitTokenFromEnv = exports.inferGitApiUrl = exports.inferGitClient = void 0;
|
||||
exports.getEnv = exports.getGitTokenFromEnv = exports.inferSquash = exports.inferGitApiUrl = exports.inferGitClient = void 0;
|
||||
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const configs_types_1 = __nccwpck_require__(4753);
|
||||
const PUBLIC_GITHUB_URL = "https://github.com";
|
||||
|
@ -673,6 +682,30 @@ const inferGitApiUrl = (prUrl, apiVersion = "v4") => {
|
|||
return `${baseUrl}/api/${apiVersion}`;
|
||||
};
|
||||
exports.inferGitApiUrl = inferGitApiUrl;
|
||||
/**
|
||||
* Infer the value of the squash option
|
||||
* @param open true if the pull/merge request is still open
|
||||
* @param squash_commit undefined if the pull/merge request was merged, the sha of the squashed commit if it was squashed
|
||||
* @returns true if a single commit must be cherry-picked, false if all merged commits must be cherry-picked
|
||||
*/
|
||||
const inferSquash = (open, squash_commit) => {
|
||||
const logger = logger_service_factory_1.default.getLogger();
|
||||
if (open) {
|
||||
logger.debug("cherry-pick all commits because they have not been merged (or squashed) in the base branch yet");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (squash_commit !== undefined) {
|
||||
logger.debug(`cherry-pick the squashed commit ${squash_commit}`);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.debug("cherry-pick the merged commit(s)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.inferSquash = inferSquash;
|
||||
/**
|
||||
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
|
||||
* All specific git env variable have precedence and override the default one.
|
||||
|
@ -748,6 +781,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const git_util_1 = __nccwpck_require__(9080);
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
|
||||
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
|
||||
|
@ -770,13 +804,28 @@ class GitHubClient {
|
|||
getDefaultGitEmail() {
|
||||
return "noreply@github.com";
|
||||
}
|
||||
async getPullRequest(owner, repo, prNumber, squash = true) {
|
||||
async getPullRequest(owner, repo, prNumber, squash) {
|
||||
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
|
||||
const { data } = await this.octokit.rest.pulls.get({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: prNumber,
|
||||
});
|
||||
if (squash === undefined) {
|
||||
let commit_sha = undefined;
|
||||
const open = data.state == "open";
|
||||
if (!open) {
|
||||
const commit = await this.octokit.rest.git.getCommit({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
commit_sha: data.merge_commit_sha,
|
||||
});
|
||||
if (commit.data.parents.length === 1) {
|
||||
commit_sha = data.merge_commit_sha;
|
||||
}
|
||||
}
|
||||
squash = (0, git_util_1.inferSquash)(open, commit_sha);
|
||||
}
|
||||
const commits = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -794,7 +843,7 @@ class GitHubClient {
|
|||
}
|
||||
return this.mapper.mapPullRequest(data, commits);
|
||||
}
|
||||
async getPullRequestFromUrl(prUrl, squash = true) {
|
||||
async getPullRequestFromUrl(prUrl, squash) {
|
||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||
return this.getPullRequest(owner, project, id, squash);
|
||||
}
|
||||
|
@ -973,6 +1022,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const git_util_1 = __nccwpck_require__(9080);
|
||||
const git_types_1 = __nccwpck_require__(750);
|
||||
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
|
||||
const gitlab_mapper_1 = __importDefault(__nccwpck_require__(2675));
|
||||
|
@ -1005,9 +1055,12 @@ class GitLabClient {
|
|||
}
|
||||
// READ
|
||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||
async getPullRequest(namespace, repo, mrNumber, squash = true) {
|
||||
async getPullRequest(namespace, repo, mrNumber, squash) {
|
||||
const projectId = this.getProjectId(namespace, repo);
|
||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||
if (squash === undefined) {
|
||||
squash = (0, git_util_1.inferSquash)(data.state == "opened", data.squash_commit_sha);
|
||||
}
|
||||
const commits = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -1022,7 +1075,7 @@ class GitLabClient {
|
|||
}
|
||||
return this.mapper.mapPullRequest(data, commits);
|
||||
}
|
||||
getPullRequestFromUrl(mrUrl, squash = true) {
|
||||
getPullRequestFromUrl(mrUrl, squash) {
|
||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||
return this.getPullRequest(namespace, project, id, squash);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ export default abstract class ArgsParser {
|
|||
labels: this.getOrDefault(args.labels, []),
|
||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||
squash: this.getOrDefault(args.squash, true),
|
||||
autoNoSquash: this.getOrDefault(args.autoNoSquash, false),
|
||||
strategy: this.getOrDefault(args.strategy),
|
||||
strategyOption: this.getOrDefault(args.strategyOption),
|
||||
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
|
||||
|
|
|
@ -22,7 +22,8 @@ export interface Args {
|
|||
inheritReviewers?: boolean, // if true and reviewers == [] then inherit reviewers from original pr
|
||||
labels?: string[], // backport pr labels
|
||||
inheritLabels?: boolean, // if true inherit labels from original pr
|
||||
squash?: boolean, // if false use squashed/merged commit otherwise backport all commits as part of the pr
|
||||
squash?: boolean,
|
||||
autoNoSquash?: boolean,
|
||||
strategy?: string, // cherry-pick merge strategy
|
||||
strategyOption?: string, // cherry-pick merge strategy option
|
||||
cherryPickOptions?: string, // additional cherry-pick options
|
||||
|
|
|
@ -28,7 +28,8 @@ export default class CLIArgsParser extends ArgsParser {
|
|||
.option("--no-inherit-reviewers", "if provided and reviewers option is empty then inherit them from original pull request")
|
||||
.option("--labels <labels>", "comma separated list of labels to be assigned to the backported pull request", getAsCommaSeparatedList)
|
||||
.option("--inherit-labels", "if true the backported pull request will inherit labels from the original one")
|
||||
.option("--no-squash", "if provided the tool will backport all commits as part of the pull request")
|
||||
.option("--no-squash", "Backport all commits found in the pull request. The default behavior is to only backport the first commit that was merged in the base branch")
|
||||
.option("--auto-no-squash", "If the pull request was merged or is open, backport all commits. If the pull request commits were squashed, backport the squashed commit.")
|
||||
.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("--cherry-pick-options <options>", "additional cherry-pick options")
|
||||
|
@ -66,6 +67,7 @@ export default class CLIArgsParser extends ArgsParser {
|
|||
labels: opts.labels,
|
||||
inheritLabels: opts.inheritLabels,
|
||||
squash: opts.squash,
|
||||
autoNoSquash: opts.autoNoSquash,
|
||||
strategy: opts.strategy,
|
||||
strategyOption: opts.strategyOption,
|
||||
cherryPickOptions: opts.cherryPickOptions,
|
||||
|
|
|
@ -32,6 +32,7 @@ export default class GHAArgsParser extends ArgsParser {
|
|||
labels: getAsCommaSeparatedList(getInput("labels")),
|
||||
inheritLabels: getAsBooleanOrDefault(getInput("inherit-labels")),
|
||||
squash: !getAsBooleanOrDefault(getInput("no-squash")),
|
||||
autoNoSquash: getAsBooleanOrDefault(getInput("auto-no-squash")),
|
||||
strategy: getOrUndefined(getInput("strategy")),
|
||||
strategyOption: getOrUndefined(getInput("strategy-option")),
|
||||
cherryPickOptions: getOrUndefined(getInput("cherry-pick-options")),
|
||||
|
|
|
@ -16,9 +16,12 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
|||
}
|
||||
|
||||
public async parse(args: Args): Promise<Configs> {
|
||||
let pr: GitPullRequest;
|
||||
let pr: GitPullRequest;
|
||||
if (args.autoNoSquash) {
|
||||
args.squash = undefined;
|
||||
}
|
||||
try {
|
||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash!);
|
||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash);
|
||||
} catch(error) {
|
||||
this.logger.error("Something went wrong retrieving pull request");
|
||||
throw error;
|
||||
|
|
|
@ -25,7 +25,7 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
|||
* @param squash if true keep just one single commit, otherwise get the full list
|
||||
* @returns {Promise<PullRequest>}
|
||||
*/
|
||||
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean): Promise<GitPullRequest>;
|
||||
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean | undefined): Promise<GitPullRequest>;
|
||||
|
||||
/**
|
||||
* Get a pull request object from the underneath git service
|
||||
|
@ -33,7 +33,7 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
|||
* @param squash if true keep just one single commit, otherwise get the full list
|
||||
* @returns {Promise<PullRequest>}
|
||||
*/
|
||||
getPullRequestFromUrl(prUrl: string, squash: boolean): Promise<GitPullRequest>;
|
||||
getPullRequestFromUrl(prUrl: string, squash: boolean | undefined): Promise<GitPullRequest>;
|
||||
|
||||
// WRITE
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
import { AuthTokenId } from "@bp/service/configs/configs.types";
|
||||
|
||||
|
@ -41,6 +42,29 @@ export const inferGitApiUrl = (prUrl: string, apiVersion = "v4"): string => {
|
|||
return `${baseUrl}/api/${apiVersion}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Infer the value of the squash option
|
||||
* @param open true if the pull/merge request is still open
|
||||
* @param squash_commit undefined if the pull/merge request was merged, the sha of the squashed commit if it was squashed
|
||||
* @returns true if a single commit must be cherry-picked, false if all merged commits must be cherry-picked
|
||||
*/
|
||||
export const inferSquash = (open: boolean, squash_commit: string | undefined): boolean => {
|
||||
const logger = LoggerServiceFactory.getLogger();
|
||||
|
||||
if (open) {
|
||||
logger.debug("cherry-pick all commits because they have not been merged (or squashed) in the base branch yet");
|
||||
return false;
|
||||
} else {
|
||||
if (squash_commit !== undefined) {
|
||||
logger.debug(`cherry-pick the squashed commit ${squash_commit}`);
|
||||
return true;
|
||||
} else {
|
||||
logger.debug("cherry-pick the merged commit(s)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
|
||||
* All specific git env variable have precedence and override the default one.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import GitClient from "@bp/service/git/git-client";
|
||||
import { inferSquash } from "@bp/service/git/git-util";
|
||||
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
|
||||
import GitHubMapper from "@bp/service/git/github/github-mapper";
|
||||
import OctokitFactory from "@bp/service/git/github/octokit-factory";
|
||||
|
@ -37,7 +38,7 @@ export default class GitHubClient implements GitClient {
|
|||
return "noreply@github.com";
|
||||
}
|
||||
|
||||
async getPullRequest(owner: string, repo: string, prNumber: number, squash = true): Promise<GitPullRequest> {
|
||||
async getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
|
||||
const { data } = await this.octokit.rest.pulls.get({
|
||||
owner: owner,
|
||||
|
@ -45,6 +46,22 @@ export default class GitHubClient implements GitClient {
|
|||
pull_number: prNumber,
|
||||
});
|
||||
|
||||
if (squash === undefined) {
|
||||
let commit_sha: string | undefined = undefined;
|
||||
const open: boolean = data.state == "open";
|
||||
if (!open) {
|
||||
const commit = await this.octokit.rest.git.getCommit({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
commit_sha: (data.merge_commit_sha as string),
|
||||
});
|
||||
if (commit.data.parents.length === 1) {
|
||||
commit_sha = (data.merge_commit_sha as string);
|
||||
}
|
||||
}
|
||||
squash = inferSquash(open, commit_sha);
|
||||
}
|
||||
|
||||
const commits: string[] = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -64,7 +81,7 @@ export default class GitHubClient implements GitClient {
|
|||
return this.mapper.mapPullRequest(data as PullRequest, commits);
|
||||
}
|
||||
|
||||
async getPullRequestFromUrl(prUrl: string, squash = true): Promise<GitPullRequest> {
|
||||
async getPullRequestFromUrl(prUrl: string, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||
return this.getPullRequest(owner, project, id, squash);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import LoggerService from "@bp/service/logger/logger-service";
|
||||
import GitClient from "@bp/service/git/git-client";
|
||||
import { inferSquash } from "@bp/service/git/git-util";
|
||||
import { GitPullRequest, BackportPullRequest, GitClientType } from "@bp/service/git/git.types";
|
||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { CommitSchema, MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
||||
|
@ -45,10 +46,14 @@ export default class GitLabClient implements GitClient {
|
|||
// READ
|
||||
|
||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||
async getPullRequest(namespace: string, repo: string, mrNumber: number, squash = true): Promise<GitPullRequest> {
|
||||
async getPullRequest(namespace: string, repo: string, mrNumber: number, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||
const projectId = this.getProjectId(namespace, repo);
|
||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||
|
||||
if (squash === undefined) {
|
||||
squash = inferSquash(data.state === "opened", data.squash_commit_sha);
|
||||
}
|
||||
|
||||
const commits: string[] = [];
|
||||
if (!squash) {
|
||||
// fetch all commits
|
||||
|
@ -65,7 +70,7 @@ export default class GitLabClient implements GitClient {
|
|||
return this.mapper.mapPullRequest(data as MergeRequestSchema, commits);
|
||||
}
|
||||
|
||||
getPullRequestFromUrl(mrUrl: string, squash = true): Promise<GitPullRequest> {
|
||||
getPullRequestFromUrl(mrUrl: string, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||
return this.getPullRequest(namespace, project, id, squash);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -129,7 +129,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -202,7 +202,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -275,7 +275,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -182,9 +182,9 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 4444, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 4444, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
|
@ -217,8 +217,7 @@ describe("github pull request config parser", () => {
|
|||
},
|
||||
bpBranchName: undefined,
|
||||
nCommits: 2,
|
||||
// taken from head.sha
|
||||
commits: ["91748965051fae1330ad58d15cf694e103267c87"]
|
||||
commits: ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -258,7 +257,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -331,7 +330,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -372,7 +371,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -444,7 +443,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -518,7 +517,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -791,7 +790,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
@ -888,7 +887,7 @@ describe("github pull request config parser", () => {
|
|||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: [],
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -123,6 +124,7 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: [],
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -195,7 +197,8 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: [],
|
||||
bpBranchName: "custom-branch"
|
||||
bpBranchName: "custom-branch",
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -268,7 +271,8 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: [],
|
||||
bpBranchName: "custom1, custom2, custom3"
|
||||
bpBranchName: "custom1, custom2, custom3",
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
|
|
@ -88,6 +88,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -158,6 +159,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -187,6 +189,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -243,6 +246,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
await expect(() => configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged");
|
||||
|
@ -262,6 +266,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -333,6 +338,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: ["user1", "user2"],
|
||||
assignees: ["user3", "user4"],
|
||||
inheritReviewers: true, // not taken into account
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -404,6 +410,7 @@ describe("gitlab merge request config parser", () => {
|
|||
reviewers: [],
|
||||
assignees: ["user3", "user4"],
|
||||
inheritReviewers: false,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -477,6 +484,7 @@ describe("gitlab merge request config parser", () => {
|
|||
inheritReviewers: false,
|
||||
labels: ["custom-label", "backport-prod"], // also include the one inherited
|
||||
inheritLabels: true,
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -742,6 +750,7 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: ["First comment", "Second comment"],
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
@ -816,6 +825,7 @@ describe("gitlab merge request config parser", () => {
|
|||
labels: [],
|
||||
inheritLabels: false,
|
||||
comments: ["First comment", "Second comment"],
|
||||
squash: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await configParser.parseAndValidate(args);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { inferGitApiUrl, inferGitClient } from "@bp/service/git/git-util";
|
||||
import { inferGitApiUrl, inferGitClient, inferSquash } from "@bp/service/git/git-util";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
|
||||
describe("check git utilities", () => {
|
||||
|
@ -54,4 +54,10 @@ describe("check git utilities", () => {
|
|||
test("check infer codeberg client", ()=> {
|
||||
expect(inferGitClient("https://codeberg.org/lampajr/backporting-example/pulls/1")).toStrictEqual(GitClientType.CODEBERG);
|
||||
});
|
||||
});
|
||||
|
||||
test("check inferSquash", ()=> {
|
||||
expect(inferSquash(true, undefined)).toStrictEqual(false);
|
||||
expect(inferSquash(false, "SHA")).toStrictEqual(true);
|
||||
expect(inferSquash(false, undefined)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,7 +22,7 @@ describe("github service", () => {
|
|||
});
|
||||
|
||||
test("get pull request: success", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequest(TARGET_OWNER, REPO, MERGED_PR_FIXTURE.number);
|
||||
const res: GitPullRequest = await gitClient.getPullRequest(TARGET_OWNER, REPO, MERGED_PR_FIXTURE.number, true);
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "fork",
|
||||
project: "reponame",
|
||||
|
|
|
@ -31,7 +31,7 @@ describe("github service", () => {
|
|||
});
|
||||
|
||||
test("get merged pull request", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 1);
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 1, true);
|
||||
|
||||
// check content
|
||||
expect(res.sourceRepo).toEqual({
|
||||
|
@ -56,7 +56,7 @@ describe("github service", () => {
|
|||
});
|
||||
|
||||
test("get open pull request", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 2);
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 2, true);
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
|
@ -325,7 +325,7 @@ describe("github service", () => {
|
|||
});
|
||||
|
||||
test("get pull request for nested namespaces", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequestFromUrl("https://my.gitlab.host.com/mysuperorg/6/mysuperproduct/mysuperunit/backporting-example/-/merge_requests/4");
|
||||
const res: GitPullRequest = await gitClient.getPullRequestFromUrl("https://my.gitlab.host.com/mysuperorg/6/mysuperproduct/mysuperunit/backporting-example/-/merge_requests/4", true);
|
||||
|
||||
// check content
|
||||
expect(res.sourceRepo).toEqual({
|
||||
|
|
|
@ -300,7 +300,7 @@ describe("cli runner", () => {
|
|||
await expect(() => runner.execute()).rejects.toThrow("Provided pull request is closed and not merged");
|
||||
});
|
||||
|
||||
test("open pull request", async () => {
|
||||
test("open pull request simple", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
|
@ -347,6 +347,55 @@ describe("cli runner", () => {
|
|||
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||
});
|
||||
|
||||
test("open pull request with --auto-no-squash", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://github.com/owner/reponame/pull/4444",
|
||||
"--auto-no-squash",
|
||||
]);
|
||||
|
||||
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-0404fb9-11da4e3");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||
expect(GitCLIService.prototype.cherryPick).toHaveBeenLastCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined, undefined);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined, undefined);
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-0404fb9-11da4e3",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: "**Backport:** https://github.com/owner/reponame/pull/4444\r\n\r\nPlease review and merge",
|
||||
reviewers: ["gh-user"],
|
||||
assignees: [],
|
||||
labels: [],
|
||||
comments: [],
|
||||
}
|
||||
);
|
||||
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||
});
|
||||
|
||||
test("override backporting pr data", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { Moctokit } from "@kie/mock-github";
|
||||
import { TARGET_OWNER, REPO, MERGED_PR_FIXTURE, OPEN_PR_FIXTURE, NOT_MERGED_PR_FIXTURE, NOT_FOUND_PR_NUMBER, MULT_COMMITS_PR_FIXTURE, MULT_COMMITS_PR_COMMITS, NEW_PR_URL, NEW_PR_NUMBER } from "./github-data";
|
||||
import { TARGET_OWNER, REPO, MERGED_PR_FIXTURE, OPEN_PR_FIXTURE, NOT_MERGED_PR_FIXTURE, NOT_FOUND_PR_NUMBER, MULT_COMMITS_PR_FIXTURE, MULT_COMMITS_PR_COMMITS, NEW_PR_URL, NEW_PR_NUMBER, GITHUB_GET_COMMIT } from "./github-data";
|
||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, NESTED_NAMESPACE_MR, OPEN_MR, OPEN_PR_COMMITS, PROJECT_EXAMPLE, NESTED_PROJECT_EXAMPLE, SUPERUSER, MERGED_SQUASHED_MR_COMMITS } from "./gitlab-data";
|
||||
|
||||
// high number, for each test we are not expecting
|
||||
|
@ -157,6 +157,17 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
|||
data: MULT_COMMITS_PR_COMMITS
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.listCommits({
|
||||
owner: TARGET_OWNER,
|
||||
repo: REPO,
|
||||
pull_number: OPEN_PR_FIXTURE.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: MULT_COMMITS_PR_COMMITS
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.create()
|
||||
.reply({
|
||||
|
@ -200,6 +211,17 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
|||
data: {}
|
||||
});
|
||||
|
||||
mock.rest.git
|
||||
.getCommit({
|
||||
owner: TARGET_OWNER,
|
||||
repo: REPO,
|
||||
commit_sha: "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: GITHUB_GET_COMMIT,
|
||||
});
|
||||
|
||||
// invalid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
|
|
|
@ -1832,6 +1832,14 @@ export const MULT_COMMITS_PR_FIXTURE = {
|
|||
"changed_files": 2
|
||||
};
|
||||
|
||||
export const GITHUB_GET_COMMIT = {
|
||||
"parents": [
|
||||
{
|
||||
"sha": "SHA"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const MULT_COMMITS_PR_COMMITS = [
|
||||
{
|
||||
"sha": "0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||
|
|
Loading…
Add table
Reference in a new issue