mirror of
https://github.com/kiegroup/git-backporting.git
synced 2025-04-24 20:32:14 +00:00
feat(issue-17): override backporting pr data (#29)
This commit is contained in:
parent
1732481b37
commit
941beda208
15 changed files with 279 additions and 30 deletions
|
@ -51,8 +51,13 @@ This toold comes with some inputs that allow users to override the default behav
|
||||||
| Pull Request | -pr, --pull-request | Y | Original pull request url, the one that must be backported, e.g., https://github.com/lampajr/backporting/pull/1 | |
|
| Pull Request | -pr, --pull-request | Y | Original pull request url, the one that must be backported, e.g., https://github.com/lampajr/backporting/pull/1 | |
|
||||||
| Auth | -a, --auth | N | `GITHUB_TOKEN` or a `repo` scoped [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) | "" |
|
| Auth | -a, --auth | N | `GITHUB_TOKEN` or a `repo` scoped [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) | "" |
|
||||||
| Folder | -f, --folder | N | Local folder where the repo will be checked out, e.g., /tmp/folder | {cwd}/bp |
|
| Folder | -f, --folder | N | Local folder where the repo will be checked out, e.g., /tmp/folder | {cwd}/bp |
|
||||||
|
| Title | --title | N | Backporting pull request title | "{original-pr-title}" |
|
||||||
|
| Body | --body | N | Backporting pull request body | "{original-pr-body}" |
|
||||||
|
| Body Prefix | --body-prefix | N | Prefix to the backporting pull request body | "Backport: {original-pr-link}" |
|
||||||
|
| Backport Branch Name | --bp-branch-name | N | Name of the backporting pull request branch | bp-{target-branch}-{sha} |
|
||||||
| 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 |
|
||||||
|
|
||||||
|
|
||||||
## GitHub Action
|
## GitHub Action
|
||||||
|
|
||||||
This action can be used in any GitHub workflow, below you can find a simple example of manually triggered workflow backporting a specific pull request (provided as input).
|
This action can be used in any GitHub workflow, below you can find a simple example of manually triggered workflow backporting a specific pull request (provided as input).
|
||||||
|
@ -135,13 +140,11 @@ For a complete description of all inputs see [Inputs section](#inputs).
|
||||||
|
|
||||||
**BPer** is in development mode, this means that it has many limitations right now. I'll try to summarize the most importan ones:
|
**BPer** is in development mode, this means that it has many limitations right now. I'll try to summarize the most importan ones:
|
||||||
|
|
||||||
- No way to override backporting pull request fields like body, reviewers and so on.
|
|
||||||
- You can backport pull requests only.
|
- You can backport pull requests only.
|
||||||
- It only works for [GitHub](https://github.com/).
|
- It only works for [GitHub](https://github.com/).
|
||||||
- Integrated in GitHub Actions CI/CD only.
|
- Integrated in GitHub Actions CI/CD only.
|
||||||
|
|
||||||
Based on these limitations, the next **Future Works** could be the following:
|
Based on these limitations, the next **Future Works** could be the following:
|
||||||
- Give users the possibility to override/customize the backporting pull request.
|
|
||||||
- Provide a way to backport single commit too (or a set of them), even if no original pull request is present.
|
- Provide a way to backport single commit too (or a set of them), even if no original pull request is present.
|
||||||
- Integrate this tool with other git management services (like GitLab and Bitbucket) to make it as generic as possible.
|
- Integrate this tool with other git management services (like GitLab and Bitbucket) to make it as generic as possible.
|
||||||
- Provide some reusable GitHub workflows.
|
- Provide some reusable GitHub workflows.
|
||||||
|
|
12
action.yml
12
action.yml
|
@ -15,6 +15,18 @@ inputs:
|
||||||
target-branch:
|
target-branch:
|
||||||
description: "Branch where the pull request must be backported to."
|
description: "Branch where the pull request must be backported to."
|
||||||
required: true
|
required: true
|
||||||
|
title:
|
||||||
|
description: "Backporting PR title. Default is the original PR title prefixed by the target branch."
|
||||||
|
required: false
|
||||||
|
body:
|
||||||
|
description: "Backporting PR body. Default is the original PR body prefixed by `backport: <original-pr-link>`."
|
||||||
|
required: false
|
||||||
|
body-prefix:
|
||||||
|
description: "Backporting PR body prefix. Default is `backport: <original-pr-link>`"
|
||||||
|
required: false
|
||||||
|
bp-branch-name:
|
||||||
|
description: "Backporting PR branch name. Default is auto-generated from commit."
|
||||||
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node16
|
using: node16
|
||||||
|
|
27
dist/cli/index.js
vendored
27
dist/cli/index.js
vendored
|
@ -39,7 +39,11 @@ class CLIArgsParser {
|
||||||
.requiredOption("-pr, --pull-request <pr url>", "pull request url, e.g., https://github.com/lampajr/backporting/pull/1.")
|
.requiredOption("-pr, --pull-request <pr url>", "pull request url, e.g., https://github.com/lampajr/backporting/pull/1.")
|
||||||
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely", false)
|
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely", false)
|
||||||
.option("-a, --auth <auth>", "git service authentication string, e.g., github token.", "")
|
.option("-a, --auth <auth>", "git service authentication string, e.g., github token.", "")
|
||||||
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder.", undefined);
|
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder.", undefined)
|
||||||
|
.option("--title <folder>", "backport pr title, default original pr title prefixed by target branch.", undefined)
|
||||||
|
.option("--body <folder>", "backport pr title, default original pr body prefixed by bodyPrefix.", undefined)
|
||||||
|
.option("--body-prefix <folder>", "backport pr body prefix, default `backport <original-pr-link>`.", undefined)
|
||||||
|
.option("--bp-branch-name <folder>", "backport pr branch name, default auto-generated by the commit.", undefined);
|
||||||
}
|
}
|
||||||
parse() {
|
parse() {
|
||||||
const opts = this.getCommand()
|
const opts = this.getCommand()
|
||||||
|
@ -50,7 +54,11 @@ class CLIArgsParser {
|
||||||
auth: opts.auth,
|
auth: opts.auth,
|
||||||
pullRequest: opts.pullRequest,
|
pullRequest: opts.pullRequest,
|
||||||
targetBranch: opts.targetBranch,
|
targetBranch: opts.targetBranch,
|
||||||
folder: opts.folder
|
folder: opts.folder,
|
||||||
|
title: opts.title,
|
||||||
|
body: opts.body,
|
||||||
|
bodyPrefix: opts.bodyPrefix,
|
||||||
|
bpBranchName: opts.bpBranchName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,32 +130,35 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
||||||
targetBranch: args.targetBranch,
|
targetBranch: args.targetBranch,
|
||||||
originalPullRequest: pr,
|
originalPullRequest: pr,
|
||||||
backportPullRequest: this.getDefaultBackportPullRequest(pr, args.targetBranch)
|
backportPullRequest: this.getDefaultBackportPullRequest(pr, args)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getDefaultFolder() {
|
getDefaultFolder() {
|
||||||
return "bp";
|
return "bp";
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Create a default backport pull request starting from the target branch and
|
* Create a backport pull request starting from the target branch and
|
||||||
* the original pr to be backported
|
* the original pr to be backported
|
||||||
* @param originalPullRequest original pull request
|
* @param originalPullRequest original pull request
|
||||||
* @param targetBranch target branch where the backport should be applied
|
* @param targetBranch target branch where the backport should be applied
|
||||||
* @returns {GitPullRequest}
|
* @returns {GitPullRequest}
|
||||||
*/
|
*/
|
||||||
getDefaultBackportPullRequest(originalPullRequest, targetBranch) {
|
getDefaultBackportPullRequest(originalPullRequest, args) {
|
||||||
const reviewers = [];
|
const reviewers = [];
|
||||||
reviewers.push(originalPullRequest.author);
|
reviewers.push(originalPullRequest.author);
|
||||||
if (originalPullRequest.mergedBy) {
|
if (originalPullRequest.mergedBy) {
|
||||||
reviewers.push(originalPullRequest.mergedBy);
|
reviewers.push(originalPullRequest.mergedBy);
|
||||||
}
|
}
|
||||||
|
const bodyPrefix = args.bodyPrefix ?? `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n`;
|
||||||
|
const body = args.body ?? `${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`;
|
||||||
return {
|
return {
|
||||||
author: originalPullRequest.author,
|
author: originalPullRequest.author,
|
||||||
title: `[${targetBranch}] ${originalPullRequest.title}`,
|
title: args.title ?? `[${args.targetBranch}] ${originalPullRequest.title}`,
|
||||||
body: `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`,
|
body: `${bodyPrefix}${body}`,
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
targetRepo: originalPullRequest.targetRepo,
|
targetRepo: originalPullRequest.targetRepo,
|
||||||
sourceRepo: originalPullRequest.targetRepo,
|
sourceRepo: originalPullRequest.targetRepo,
|
||||||
|
branchName: args.bpBranchName,
|
||||||
nCommits: 0,
|
nCommits: 0,
|
||||||
commits: [] // TODO needed?
|
commits: [] // TODO needed?
|
||||||
};
|
};
|
||||||
|
@ -649,7 +660,7 @@ class Runner {
|
||||||
// 4. clone the repository
|
// 4. clone the repository
|
||||||
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
||||||
// 5. create new branch from target one and checkout
|
// 5. create new branch from target one and checkout
|
||||||
const backportBranch = `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
const backportBranch = backportPR.branchName ?? `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
||||||
await git.createLocalBranch(configs.folder, backportBranch);
|
await git.createLocalBranch(configs.folder, backportBranch);
|
||||||
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
||||||
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
|
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
|
||||||
|
|
21
dist/gha/index.js
vendored
21
dist/gha/index.js
vendored
|
@ -36,7 +36,11 @@ class GHAArgsParser {
|
||||||
auth: (0, core_1.getInput)("auth") ? (0, core_1.getInput)("auth") : "",
|
auth: (0, core_1.getInput)("auth") ? (0, core_1.getInput)("auth") : "",
|
||||||
pullRequest: (0, core_1.getInput)("pull-request"),
|
pullRequest: (0, core_1.getInput)("pull-request"),
|
||||||
targetBranch: (0, core_1.getInput)("target-branch"),
|
targetBranch: (0, core_1.getInput)("target-branch"),
|
||||||
folder: (0, core_1.getInput)("folder") !== "" ? (0, core_1.getInput)("folder") : undefined
|
folder: (0, core_1.getInput)("folder") !== "" ? (0, core_1.getInput)("folder") : undefined,
|
||||||
|
title: (0, core_1.getInput)("title"),
|
||||||
|
body: (0, core_1.getInput)("body"),
|
||||||
|
bodyPrefix: (0, core_1.getInput)("body-prefix"),
|
||||||
|
bpBranchName: (0, core_1.getInput)("bp-branch-name"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,32 +112,35 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
||||||
targetBranch: args.targetBranch,
|
targetBranch: args.targetBranch,
|
||||||
originalPullRequest: pr,
|
originalPullRequest: pr,
|
||||||
backportPullRequest: this.getDefaultBackportPullRequest(pr, args.targetBranch)
|
backportPullRequest: this.getDefaultBackportPullRequest(pr, args)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getDefaultFolder() {
|
getDefaultFolder() {
|
||||||
return "bp";
|
return "bp";
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Create a default backport pull request starting from the target branch and
|
* Create a backport pull request starting from the target branch and
|
||||||
* the original pr to be backported
|
* the original pr to be backported
|
||||||
* @param originalPullRequest original pull request
|
* @param originalPullRequest original pull request
|
||||||
* @param targetBranch target branch where the backport should be applied
|
* @param targetBranch target branch where the backport should be applied
|
||||||
* @returns {GitPullRequest}
|
* @returns {GitPullRequest}
|
||||||
*/
|
*/
|
||||||
getDefaultBackportPullRequest(originalPullRequest, targetBranch) {
|
getDefaultBackportPullRequest(originalPullRequest, args) {
|
||||||
const reviewers = [];
|
const reviewers = [];
|
||||||
reviewers.push(originalPullRequest.author);
|
reviewers.push(originalPullRequest.author);
|
||||||
if (originalPullRequest.mergedBy) {
|
if (originalPullRequest.mergedBy) {
|
||||||
reviewers.push(originalPullRequest.mergedBy);
|
reviewers.push(originalPullRequest.mergedBy);
|
||||||
}
|
}
|
||||||
|
const bodyPrefix = args.bodyPrefix ?? `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n`;
|
||||||
|
const body = args.body ?? `${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`;
|
||||||
return {
|
return {
|
||||||
author: originalPullRequest.author,
|
author: originalPullRequest.author,
|
||||||
title: `[${targetBranch}] ${originalPullRequest.title}`,
|
title: args.title ?? `[${args.targetBranch}] ${originalPullRequest.title}`,
|
||||||
body: `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`,
|
body: `${bodyPrefix}${body}`,
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
targetRepo: originalPullRequest.targetRepo,
|
targetRepo: originalPullRequest.targetRepo,
|
||||||
sourceRepo: originalPullRequest.targetRepo,
|
sourceRepo: originalPullRequest.targetRepo,
|
||||||
|
branchName: args.bpBranchName,
|
||||||
nCommits: 0,
|
nCommits: 0,
|
||||||
commits: [] // TODO needed?
|
commits: [] // TODO needed?
|
||||||
};
|
};
|
||||||
|
@ -635,7 +642,7 @@ class Runner {
|
||||||
// 4. clone the repository
|
// 4. clone the repository
|
||||||
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
||||||
// 5. create new branch from target one and checkout
|
// 5. create new branch from target one and checkout
|
||||||
const backportBranch = `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
const backportBranch = backportPR.branchName ?? `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
||||||
await git.createLocalBranch(configs.folder, backportBranch);
|
await git.createLocalBranch(configs.folder, backportBranch);
|
||||||
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
||||||
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
|
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
|
||||||
|
|
|
@ -8,4 +8,8 @@ export interface Args {
|
||||||
pullRequest: string, // url of the pull request to backport
|
pullRequest: string, // url of the pull request to backport
|
||||||
folder?: string, // local folder where the repositories should be cloned
|
folder?: string, // local folder where the repositories should be cloned
|
||||||
author?: string, // backport pr author, default taken from pr
|
author?: string, // backport pr author, default taken from pr
|
||||||
|
title?: string, // backport pr title, default original pr title prefixed by target branch
|
||||||
|
body?: string, // backport pr title, default original pr body prefixed by bodyPrefix
|
||||||
|
bodyPrefix?: string, // backport pr body prefix, default `backport <original-pr-link>`
|
||||||
|
bpBranchName?: string, // backport pr branch name, default computed from commit
|
||||||
}
|
}
|
|
@ -14,7 +14,11 @@ export default class CLIArgsParser implements ArgsParser {
|
||||||
.requiredOption("-pr, --pull-request <pr url>", "pull request url, e.g., https://github.com/lampajr/backporting/pull/1.")
|
.requiredOption("-pr, --pull-request <pr url>", "pull request url, e.g., https://github.com/lampajr/backporting/pull/1.")
|
||||||
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely", false)
|
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely", false)
|
||||||
.option("-a, --auth <auth>", "git service authentication string, e.g., github token.", "")
|
.option("-a, --auth <auth>", "git service authentication string, e.g., github token.", "")
|
||||||
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder.", undefined);
|
.option("-f, --folder <folder>", "local folder where the repo will be checked out, e.g., /tmp/folder.", undefined)
|
||||||
|
.option("--title <folder>", "backport pr title, default original pr title prefixed by target branch.", undefined)
|
||||||
|
.option("--body <folder>", "backport pr title, default original pr body prefixed by bodyPrefix.", undefined)
|
||||||
|
.option("--body-prefix <folder>", "backport pr body prefix, default `backport <original-pr-link>`.", undefined)
|
||||||
|
.option("--bp-branch-name <folder>", "backport pr branch name, default auto-generated by the commit.", undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(): Args {
|
parse(): Args {
|
||||||
|
@ -27,7 +31,11 @@ export default class CLIArgsParser implements ArgsParser {
|
||||||
auth: opts.auth,
|
auth: opts.auth,
|
||||||
pullRequest: opts.pullRequest,
|
pullRequest: opts.pullRequest,
|
||||||
targetBranch: opts.targetBranch,
|
targetBranch: opts.targetBranch,
|
||||||
folder: opts.folder
|
folder: opts.folder,
|
||||||
|
title: opts.title,
|
||||||
|
body: opts.body,
|
||||||
|
bodyPrefix: opts.bodyPrefix,
|
||||||
|
bpBranchName: opts.bpBranchName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@ export default class GHAArgsParser implements ArgsParser {
|
||||||
auth: getInput("auth") ? getInput("auth") : "",
|
auth: getInput("auth") ? getInput("auth") : "",
|
||||||
pullRequest: getInput("pull-request"),
|
pullRequest: getInput("pull-request"),
|
||||||
targetBranch: getInput("target-branch"),
|
targetBranch: getInput("target-branch"),
|
||||||
folder: getInput("folder") !== "" ? getInput("folder") : undefined
|
folder: getInput("folder") !== "" ? getInput("folder") : undefined,
|
||||||
|
title: getInput("title"),
|
||||||
|
body: getInput("body"),
|
||||||
|
bodyPrefix: getInput("body-prefix"),
|
||||||
|
bpBranchName: getInput("bp-branch-name"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
||||||
targetBranch: args.targetBranch,
|
targetBranch: args.targetBranch,
|
||||||
originalPullRequest: pr,
|
originalPullRequest: pr,
|
||||||
backportPullRequest: this.getDefaultBackportPullRequest(pr, args.targetBranch)
|
backportPullRequest: this.getDefaultBackportPullRequest(pr, args)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,26 +34,30 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a default backport pull request starting from the target branch and
|
* Create a backport pull request starting from the target branch and
|
||||||
* the original pr to be backported
|
* the original pr to be backported
|
||||||
* @param originalPullRequest original pull request
|
* @param originalPullRequest original pull request
|
||||||
* @param targetBranch target branch where the backport should be applied
|
* @param targetBranch target branch where the backport should be applied
|
||||||
* @returns {GitPullRequest}
|
* @returns {GitPullRequest}
|
||||||
*/
|
*/
|
||||||
private getDefaultBackportPullRequest(originalPullRequest: GitPullRequest, targetBranch: string): GitPullRequest {
|
private getDefaultBackportPullRequest(originalPullRequest: GitPullRequest, args: Args): GitPullRequest {
|
||||||
const reviewers = [];
|
const reviewers = [];
|
||||||
reviewers.push(originalPullRequest.author);
|
reviewers.push(originalPullRequest.author);
|
||||||
if (originalPullRequest.mergedBy) {
|
if (originalPullRequest.mergedBy) {
|
||||||
reviewers.push(originalPullRequest.mergedBy);
|
reviewers.push(originalPullRequest.mergedBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bodyPrefix = args.bodyPrefix ?? `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n`;
|
||||||
|
const body = args.body ?? `${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
author: originalPullRequest.author,
|
author: originalPullRequest.author,
|
||||||
title: `[${targetBranch}] ${originalPullRequest.title}`,
|
title: args.title ?? `[${args.targetBranch}] ${originalPullRequest.title}`,
|
||||||
body: `**Backport:** ${originalPullRequest.htmlUrl}\r\n\r\n${originalPullRequest.body}\r\n\r\nPowered by [BPer](https://github.com/lampajr/backporting).`,
|
body: `${bodyPrefix}${body}`,
|
||||||
reviewers: [...new Set(reviewers)],
|
reviewers: [...new Set(reviewers)],
|
||||||
targetRepo: originalPullRequest.targetRepo,
|
targetRepo: originalPullRequest.targetRepo,
|
||||||
sourceRepo: originalPullRequest.targetRepo,
|
sourceRepo: originalPullRequest.targetRepo,
|
||||||
|
branchName: args.bpBranchName,
|
||||||
nCommits: 0, // TODO: needed?
|
nCommits: 0, // TODO: needed?
|
||||||
commits: [] // TODO needed?
|
commits: [] // TODO needed?
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,8 @@ export interface GitPullRequest {
|
||||||
targetRepo: GitRepository,
|
targetRepo: GitRepository,
|
||||||
sourceRepo: GitRepository,
|
sourceRepo: GitRepository,
|
||||||
nCommits: number, // number of commits in the pr
|
nCommits: number, // number of commits in the pr
|
||||||
commits: string[] // merge commit or last one
|
commits: string[], // merge commit or last one
|
||||||
|
branchName?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GitRepository {
|
export interface GitRepository {
|
||||||
|
@ -28,7 +29,8 @@ export interface BackportPullRequest {
|
||||||
base: string, // name of the target branch
|
base: string, // name of the target branch
|
||||||
title: string, // pr title
|
title: string, // pr title
|
||||||
body: string, // pr body
|
body: string, // pr body
|
||||||
reviewers: string[] // pr list of reviewers
|
reviewers: string[], // pr list of reviewers
|
||||||
|
branchName?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum GitServiceType {
|
export enum GitServiceType {
|
||||||
|
|
|
@ -86,7 +86,7 @@ export default class Runner {
|
||||||
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
||||||
|
|
||||||
// 5. create new branch from target one and checkout
|
// 5. create new branch from target one and checkout
|
||||||
const backportBranch = `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
const backportBranch = backportPR.branchName ?? `bp-${configs.targetBranch}-${originalPR.commits.join("-")}`;
|
||||||
await git.createLocalBranch(configs.folder, backportBranch);
|
await git.createLocalBranch(configs.folder, backportBranch);
|
||||||
|
|
||||||
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
||||||
|
|
|
@ -28,6 +28,10 @@ describe("cli args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [default, long]", () => {
|
test("valid execution [default, long]", () => {
|
||||||
|
@ -45,6 +49,10 @@ describe("cli args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, short]", () => {
|
test("valid execution [override, short]", () => {
|
||||||
|
@ -65,6 +73,10 @@ describe("cli args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, long]", () => {
|
test("valid execution [override, long]", () => {
|
||||||
|
@ -75,7 +87,15 @@ describe("cli args parser", () => {
|
||||||
"--target-branch",
|
"--target-branch",
|
||||||
"target",
|
"target",
|
||||||
"--pull-request",
|
"--pull-request",
|
||||||
"https://localhost/whatever/pulls/1"
|
"https://localhost/whatever/pulls/1",
|
||||||
|
"--title",
|
||||||
|
"New Title",
|
||||||
|
"--body",
|
||||||
|
"New Body",
|
||||||
|
"--body-prefix",
|
||||||
|
"New Body Prefix",
|
||||||
|
"--bp-branch-name",
|
||||||
|
"bp_branch_name",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const args: Args = parser.parse();
|
const args: Args = parser.parse();
|
||||||
|
@ -85,6 +105,10 @@ describe("cli args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||||
|
expect(args.title).toEqual("New Title");
|
||||||
|
expect(args.body).toEqual("New Body");
|
||||||
|
expect(args.bodyPrefix).toEqual("New Body Prefix");
|
||||||
|
expect(args.bpBranchName).toEqual("bp_branch_name");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -28,6 +28,10 @@ describe("gha args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override]", () => {
|
test("valid execution [override]", () => {
|
||||||
|
@ -35,7 +39,11 @@ describe("gha args parser", () => {
|
||||||
"dry-run": "true",
|
"dry-run": "true",
|
||||||
"auth": "bearer-token",
|
"auth": "bearer-token",
|
||||||
"target-branch": "target",
|
"target-branch": "target",
|
||||||
"pull-request": "https://localhost/whatever/pulls/1"
|
"pull-request": "https://localhost/whatever/pulls/1",
|
||||||
|
"title": "New Title",
|
||||||
|
"body": "New Body",
|
||||||
|
"body-prefix": "New Body Prefix",
|
||||||
|
"bp-branch-name": "bp_branch_name",
|
||||||
});
|
});
|
||||||
|
|
||||||
const args: Args = parser.parse();
|
const args: Args = parser.parse();
|
||||||
|
@ -45,6 +53,10 @@ describe("gha args parser", () => {
|
||||||
expect(args.folder).toEqual(undefined);
|
expect(args.folder).toEqual(undefined);
|
||||||
expect(args.targetBranch).toEqual("target");
|
expect(args.targetBranch).toEqual("target");
|
||||||
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
expect(args.pullRequest).toEqual("https://localhost/whatever/pulls/1");
|
||||||
|
expect(args.title).toEqual("New Title");
|
||||||
|
expect(args.body).toEqual("New Body");
|
||||||
|
expect(args.bodyPrefix).toEqual("New Body Prefix");
|
||||||
|
expect(args.bpBranchName).toEqual("bp_branch_name");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -84,6 +84,7 @@ describe("pull request config parser", () => {
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
cloneUrl: "https://github.com/owner/reponame.git"
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
},
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
nCommits: 0,
|
nCommits: 0,
|
||||||
commits: []
|
commits: []
|
||||||
});
|
});
|
||||||
|
@ -158,6 +159,7 @@ describe("pull request config parser", () => {
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
cloneUrl: "https://github.com/fork/reponame.git"
|
cloneUrl: "https://github.com/fork/reponame.git"
|
||||||
},
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
nCommits: 2,
|
nCommits: 2,
|
||||||
// taken from head.sha
|
// taken from head.sha
|
||||||
commits: ["91748965051fae1330ad58d15cf694e103267c87"]
|
commits: ["91748965051fae1330ad58d15cf694e103267c87"]
|
||||||
|
@ -174,4 +176,70 @@ describe("pull request config parser", () => {
|
||||||
|
|
||||||
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("override backport pr data", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body",
|
||||||
|
bodyPrefix: "New Body Prefix -",
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await parser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.author).toEqual("gh-user");
|
||||||
|
expect(configs.auth).toEqual("");
|
||||||
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||||
|
expect(configs.originalPullRequest).toEqual({
|
||||||
|
number: 2368,
|
||||||
|
author: "gh-user",
|
||||||
|
url: "https://api.github.com/repos/owner/reponame/pulls/2368",
|
||||||
|
htmlUrl: "https://github.com/owner/reponame/pull/2368",
|
||||||
|
state: "closed",
|
||||||
|
merged: true,
|
||||||
|
mergedBy: "that-s-a-user",
|
||||||
|
title: "PR Title",
|
||||||
|
body: "Please review and merge",
|
||||||
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "fork",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/fork/reponame.git"
|
||||||
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
|
nCommits: 2,
|
||||||
|
commits: ["28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc"],
|
||||||
|
});
|
||||||
|
expect(configs.backportPullRequest).toEqual({
|
||||||
|
author: "gh-user",
|
||||||
|
url: undefined,
|
||||||
|
htmlUrl: undefined,
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix -New Body",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
|
nCommits: 0,
|
||||||
|
commits: []
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -282,4 +282,52 @@ describe("cli runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("override backporting pr data", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/2368",
|
||||||
|
"--title",
|
||||||
|
"New Title",
|
||||||
|
"--body",
|
||||||
|
"New Body",
|
||||||
|
"--body-prefix",
|
||||||
|
"New Body Prefix - ",
|
||||||
|
"--bp-branch-name",
|
||||||
|
"bp_branch_name",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
|
||||||
|
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp_branch_name",
|
||||||
|
base: "target",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix - New Body",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -138,4 +138,46 @@ describe("gha runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("override backporting pr data", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://github.com/owner/reponame/pull/2368",
|
||||||
|
"title": "New Title",
|
||||||
|
"body": "New Body",
|
||||||
|
"body-prefix": "New Body Prefix - ",
|
||||||
|
"bp-branch-name": "bp_branch_name",
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
|
||||||
|
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp_branch_name",
|
||||||
|
base: "target",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix - New Body",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
Loading…
Add table
Reference in a new issue