mirror of
https://github.com/kiegroup/git-backporting.git
synced 2025-04-24 20:32:14 +00:00
feat(issue-54): backport pr commits without squash
Fix https://github.com/kiegroup/git-backporting/issues/54
This commit is contained in:
parent
a737aa7c4c
commit
a2f3ff013c
29 changed files with 1004 additions and 161 deletions
33
.github/pull_request_template.md
vendored
33
.github/pull_request_template.md
vendored
|
@ -18,3 +18,36 @@ changes that span multiple kiegroup repositories and depend on each other. -->
|
||||||
- [ ] Documentation updated if applicable.
|
- [ ] Documentation updated if applicable.
|
||||||
|
|
||||||
> **Note:** `dist/cli/index.js` and `dist/gha/index.js` are automatically generated by git hooks and gh workflows.
|
> **Note:** `dist/cli/index.js` and `dist/gha/index.js` are automatically generated by git hooks and gh workflows.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
First time here?
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
This project follows [git conventional commits](https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13) pattern, therefore the commits should have the following format:
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>(<optional scope>): <subject>
|
||||||
|
empty separator line
|
||||||
|
<optional body>
|
||||||
|
empty separator line
|
||||||
|
<optional footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the type must be one of `[build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test]`
|
||||||
|
|
||||||
|
> **NOTE**: if you are still in a `work in progress` branch and you want to push your changes remotely, consider adding `--no-verify` for both `commit` and `push`, e.g., `git push origin <feat-branch> --no-verify` - this could become useful to push changes where there are still tests failures. Once the pull request is ready, please `amend` the commit and force-push it to keep following the adopted git commit standard.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
How to prepare for a new release?
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
There is no need to manually update `package.json` version and `CHANGELOG.md` information. This process has been automated in [Prepare Release](./workflows/prepare-release.yml) *Github* workflow.
|
||||||
|
|
||||||
|
Therefore whenever enough changes are merged into the `main` branch, one of the maintainers will trigger this workflow that will automatically update `version` and `changelog` based on the commits on the git tree.
|
||||||
|
|
||||||
|
More details can be found in [package release](https://github.com/kiegroup/git-backporting/blob/main/README.md#package-release) section of the README.
|
||||||
|
</details>
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,3 +11,6 @@ report.json
|
||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
.npmrc
|
.npmrc
|
||||||
|
|
||||||
|
# temporary files created during tests
|
||||||
|
*test*.json
|
105
README.md
105
README.md
|
@ -26,12 +26,11 @@ Table of content
|
||||||
|
|
||||||
* **[Who is this tool for](#who-is-this-tool-for)**
|
* **[Who is this tool for](#who-is-this-tool-for)**
|
||||||
* **[CLI tool](#cli-tool)**
|
* **[CLI tool](#cli-tool)**
|
||||||
* **[Supported git services](#supported-git-services)**
|
|
||||||
* **[GitHub action](#github-action)**
|
* **[GitHub action](#github-action)**
|
||||||
* **[Future works](#future-works)**
|
* **[Future works](#future-works)**
|
||||||
* **[Release](#release)**
|
* **[Migrating to v4](#migrating-to-v4)**
|
||||||
* **[Repository migration](#repository-migration)**
|
|
||||||
* **[Contributing](#contributing)**
|
* **[Contributing](#contributing)**
|
||||||
|
* **[Package release](#package-release)**
|
||||||
* **[License](#license)**
|
* **[License](#license)**
|
||||||
|
|
||||||
## Who is this tool for?
|
## Who is this tool for?
|
||||||
|
@ -72,6 +71,23 @@ This is the easiest invocation where you let the tool set / compute most of the
|
||||||
* Node 16 or higher, more details on Node can be found [here](https://nodejs.org/en).
|
* Node 16 or higher, more details on Node can be found [here](https://nodejs.org/en).
|
||||||
* Git, see [how to install](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if you need help.
|
* Git, see [how to install](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if you need help.
|
||||||
|
|
||||||
|
### How it works?
|
||||||
|
|
||||||
|
The simply works in this way: given the provided `pull/merge request` it infers the git client to use (either *Github* or *Gitlab* for now) and it retrieve the corresponding pull request object (original pull/merge request to be backported into another branch).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Right now all commits are cherry-picked using the following git-equivalent command:
|
||||||
|
```bash
|
||||||
|
$ git cherry-pick -m 1 --strategy=recursive --strategy-option=theirs <sha>
|
||||||
|
```
|
||||||
|
|
||||||
|
> **NOTE**: If there are any conflicts, the tool will block the process and exit signalling the failure as there are still no ways to interactively resolve them. In these cases a manual cherry-pick is needed, or alternatively users could manually resume the process in the cloned repository (here the user will have to resolve the conflicts, push the branch and create the pull request - all manually).
|
||||||
|
|
||||||
### Inputs
|
### Inputs
|
||||||
|
|
||||||
This tool comes with some inputs that allow users to override the default behavior, here the full list of available inputs:
|
This tool comes with some inputs that allow users to override the default behavior, here the full list of available inputs:
|
||||||
|
@ -96,6 +112,7 @@ This tool comes with some inputs that allow users to override the default behavi
|
||||||
| Backport Branch Name | --bp-branch-name | N | Name of the backporting pull request branch | bp-{target-branch}-{sha} |
|
| Backport Branch Name | --bp-branch-name | N | Name of the backporting pull request branch | bp-{target-branch}-{sha} |
|
||||||
| Labels | --labels | N | Provide custom labels to be added to the backporting pull request | [] |
|
| 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 |
|
| 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 |
|
||||||
| 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).
|
||||||
|
@ -114,7 +131,7 @@ This is an example of a configuration file that can be used.
|
||||||
```
|
```
|
||||||
Keep in mind that its structue MUST match the [Args](src/service/args/args.types.ts) interface, which is actually a camel-case version of the CLI options.
|
Keep in mind that its structue MUST match the [Args](src/service/args/args.types.ts) interface, which is actually a camel-case version of the CLI options.
|
||||||
|
|
||||||
## Supported git services
|
### Supported git services
|
||||||
|
|
||||||
Right now **Git Backporting** supports the following git management services:
|
Right now **Git Backporting** supports the following git management services:
|
||||||
* ***GITHUB***: Introduced since the first release of this tool (version `1.0.0`). The interaction with this system is performed using [*octokit*](https://octokit.github.io/rest.js) client library.
|
* ***GITHUB***: Introduced since the first release of this tool (version `1.0.0`). The interaction with this system is performed using [*octokit*](https://octokit.github.io/rest.js) client library.
|
||||||
|
@ -128,7 +145,7 @@ Right now **Git Backporting** supports the following git management services:
|
||||||
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).
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
name: Pull Request Backporting using BPer
|
name: Pull Request Backporting using Git Backporting
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
@ -166,7 +183,7 @@ You can also use this action with other events - you'll just need to specify `ta
|
||||||
For example, this configuration creates a pull request against branch `v1` once the current one is merged, provided that the label `backport-v1` is applied:
|
For example, this configuration creates a pull request against branch `v1` once the current one is merged, provided that the label `backport-v1` is applied:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: Pull Request Backporting using BPer
|
name: Pull Request Backporting using Git Backporting
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
|
@ -203,49 +220,14 @@ For a complete description of all inputs see [Inputs section](#inputs).
|
||||||
|
|
||||||
## Future works
|
## Future works
|
||||||
|
|
||||||
**BPer** is still in development mode, this means that there are still many future works and extension. I'll try to summarize the most important ones:
|
**Git Backporting** is still in development mode, this means that there are still many future works and extension that can be implemented. I'll try to summarize the most important ones:
|
||||||
|
|
||||||
- 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 (or a set of them) if no original pull request is present.
|
||||||
- Integrate this tool with other git management services (like Bitbucket) to make it as generic as possible.
|
- Integrate this tool with other git management services (like Bitbucket) to make it as generic as possible.
|
||||||
- Integrate it into other CI/CD services like gitlab CI.
|
- Integrate it into other CI/CD services like gitlab CI.
|
||||||
- Provide some reusable *GitHub* workflows.
|
- Provide some reusable *GitHub* workflows.
|
||||||
|
|
||||||
## Release
|
## Migrating to v4
|
||||||
|
|
||||||
The release of this package is entirely based on [release-it](https://github.com/release-it/release-it) tool. I created some useful scripts that can make the release itself quite easy.
|
|
||||||
|
|
||||||
|
|
||||||
### Automated release
|
|
||||||
|
|
||||||
The first step is to prepare the changes for the next release, this is done by running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm run release:prepare:all
|
|
||||||
```
|
|
||||||
|
|
||||||
> NOTE: running locally this requires `npm login`, please consider using `.github/workflows/prepare-release.yml` if you don't have permission on the npm package.
|
|
||||||
|
|
||||||
This script performs the following steps:
|
|
||||||
1. Automatically computes the next version based on the last commits
|
|
||||||
2. Create a new branch `release/v${computed_version}`
|
|
||||||
3. Apply all changes, like version and changelog upgrade
|
|
||||||
4. Commit those changes: `chore: release v${compute_version}`
|
|
||||||
|
|
||||||
After that you should just push the new branch and open the pull request.
|
|
||||||
> NOTE: if you don't want to run this preparation from you local environment, there is already a workflow that does all these steps, including the pull request. See [Prepare release](.github/workflows/prepare-release.yml) workflow.
|
|
||||||
|
|
||||||
Once the release preparion pull request got merged, you can run [Release package](.github/workflows/release.yml) workflow that automatically performs the release itself, including npm publishing, git tag and github release.
|
|
||||||
|
|
||||||
### Manual release
|
|
||||||
|
|
||||||
In case we would like to perform a manual release, it would be enough to open a pull request changing the following items:
|
|
||||||
- Package version inside the `package.json`
|
|
||||||
- Provide exhaustive changelog information inside `CHANGELOG.md`
|
|
||||||
- Commit like `chore: release v<version>`
|
|
||||||
|
|
||||||
Once the release preparion pull request got merged, run [Release package](.github/workflows/release.yml) workflow.
|
|
||||||
|
|
||||||
## Repository Migration
|
|
||||||
|
|
||||||
From version `v4.0.0` the project has been moved under [@kiegroup](https://github.com/kiegroup) organization. During this migration we changed some things that you should be aware of. I'll try to summarize them in the following table:
|
From version `v4.0.0` the project has been moved under [@kiegroup](https://github.com/kiegroup) organization. During this migration we changed some things that you should be aware of. I'll try to summarize them in the following table:
|
||||||
|
|
||||||
|
@ -284,6 +266,41 @@ Every change must be submitted through a *GitHub* pull request (PR). Backporting
|
||||||
|
|
||||||
**Hint**: if you are still in a `work in progress` branch and you want to push your changes remotely, consider adding `--no-verify` for both `commit` and `push`, e.g., `git push origin <feat-branch> --no-verify`
|
**Hint**: if you are still in a `work in progress` branch and you want to push your changes remotely, consider adding `--no-verify` for both `commit` and `push`, e.g., `git push origin <feat-branch> --no-verify`
|
||||||
|
|
||||||
|
## Package release
|
||||||
|
|
||||||
|
The release of this package is entirely based on [release-it](https://github.com/release-it/release-it) tool. I created some useful scripts that can make the release itself quite easy.
|
||||||
|
|
||||||
|
|
||||||
|
### Automated release
|
||||||
|
|
||||||
|
The first step is to prepare the changes for the next release, this is done by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm run release:prepare:all
|
||||||
|
```
|
||||||
|
|
||||||
|
> NOTE: running locally this requires `npm login`, please consider using `.github/workflows/prepare-release.yml` if you don't have permission on the npm package.
|
||||||
|
|
||||||
|
This script performs the following steps:
|
||||||
|
1. Automatically computes the next version based on the last commits
|
||||||
|
2. Create a new branch `release/v${computed_version}`
|
||||||
|
3. Apply all changes, like version and changelog upgrade
|
||||||
|
4. Commit those changes: `chore: release v${compute_version}`
|
||||||
|
|
||||||
|
After that you should just push the new branch and open the pull request.
|
||||||
|
> NOTE: if you don't want to run this preparation from you local environment, there is already a workflow that does all these steps, including the pull request. See [Prepare release](.github/workflows/prepare-release.yml) workflow.
|
||||||
|
|
||||||
|
Once the release preparion pull request got merged, you can run [Release package](.github/workflows/release.yml) workflow that automatically performs the release itself, including npm publishing, git tag and github release.
|
||||||
|
|
||||||
|
### Manual release
|
||||||
|
|
||||||
|
In case we would like to perform a manual release, it would be enough to open a pull request changing the following items:
|
||||||
|
- Package version inside the `package.json`
|
||||||
|
- Provide exhaustive changelog information inside `CHANGELOG.md`
|
||||||
|
- Commit like `chore: release v<version>`
|
||||||
|
|
||||||
|
Once the release preparion pull request got merged, run [Release package](.github/workflows/release.yml) workflow.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Backporting (BPer) open source project is licensed under the [MIT](./LICENSE) license.
|
Backporting (BPer) open source project is licensed under the [MIT](./LICENSE) license.
|
|
@ -55,6 +55,10 @@ inputs:
|
||||||
description: "If true the backported pull request will inherit labels from the original one"
|
description: "If true the backported pull request will inherit labels from the original one"
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
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"
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node16
|
using: node16
|
||||||
|
|
72
dist/cli/index.js
vendored
72
dist/cli/index.js
vendored
|
@ -60,6 +60,7 @@ class ArgsParser {
|
||||||
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
||||||
labels: this.getOrDefault(args.labels, []),
|
labels: this.getOrDefault(args.labels, []),
|
||||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||||
|
squash: this.getOrDefault(args.squash, true),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +186,7 @@ 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("--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("--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("--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("-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() {
|
||||||
|
@ -214,6 +216,7 @@ class CLIArgsParser extends args_parser_1.default {
|
||||||
inheritReviewers: opts.inheritReviewers,
|
inheritReviewers: opts.inheritReviewers,
|
||||||
labels: opts.labels,
|
labels: opts.labels,
|
||||||
inheritLabels: opts.inheritLabels,
|
inheritLabels: opts.inheritLabels,
|
||||||
|
squash: opts.squash,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
@ -280,7 +283,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
async parse(args) {
|
async parse(args) {
|
||||||
let pr;
|
let pr;
|
||||||
try {
|
try {
|
||||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest);
|
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
this.logger.error("Something went wrong retrieving pull request");
|
this.logger.error("Something went wrong retrieving pull request");
|
||||||
|
@ -619,18 +622,33 @@ class GitHubClient {
|
||||||
getDefaultGitEmail() {
|
getDefaultGitEmail() {
|
||||||
return "noreply@github.com";
|
return "noreply@github.com";
|
||||||
}
|
}
|
||||||
async getPullRequest(owner, repo, prNumber) {
|
async getPullRequest(owner, repo, prNumber, squash = true) {
|
||||||
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
||||||
const { data } = await this.octokit.rest.pulls.get({
|
const { data } = await this.octokit.rest.pulls.get({
|
||||||
owner: owner,
|
owner: owner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
pull_number: prNumber
|
pull_number: prNumber,
|
||||||
});
|
});
|
||||||
return this.mapper.mapPullRequest(data);
|
const commits = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.octokit.rest.pulls.listCommits({
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
commits.push(...data.map(c => c.sha));
|
||||||
}
|
}
|
||||||
async getPullRequestFromUrl(prUrl) {
|
catch (error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for pull request n. ${prNumber}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.mapper.mapPullRequest(data, commits);
|
||||||
|
}
|
||||||
|
async getPullRequestFromUrl(prUrl, squash = true) {
|
||||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||||
return this.getPullRequest(owner, project, id);
|
return this.getPullRequest(owner, project, id, squash);
|
||||||
}
|
}
|
||||||
// WRITE
|
// WRITE
|
||||||
async createPullRequest(backport) {
|
async createPullRequest(backport) {
|
||||||
|
@ -724,7 +742,7 @@ class GitHubMapper {
|
||||||
return git_types_1.GitRepoState.CLOSED;
|
return git_types_1.GitRepoState.CLOSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async mapPullRequest(pr) {
|
async mapPullRequest(pr, commits) {
|
||||||
return {
|
return {
|
||||||
number: pr.number,
|
number: pr.number,
|
||||||
author: pr.user.login,
|
author: pr.user.login,
|
||||||
|
@ -741,10 +759,14 @@ class GitHubMapper {
|
||||||
sourceRepo: await this.mapSourceRepo(pr),
|
sourceRepo: await this.mapSourceRepo(pr),
|
||||||
targetRepo: await this.mapTargetRepo(pr),
|
targetRepo: await this.mapTargetRepo(pr),
|
||||||
nCommits: pr.commits,
|
nCommits: pr.commits,
|
||||||
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
// if commits is provided use them, otherwise fetch the single sha representing the whole pr
|
||||||
commits: pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha]
|
commits: (commits && commits.length > 0) ? commits : this.getSha(pr),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
getSha(pr) {
|
||||||
|
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
||||||
|
return pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha];
|
||||||
|
}
|
||||||
async mapSourceRepo(pr) {
|
async mapSourceRepo(pr) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
owner: pr.head.repo.full_name.split("/")[0],
|
owner: pr.head.repo.full_name.split("/")[0],
|
||||||
|
@ -835,14 +857,26 @@ class GitLabClient {
|
||||||
}
|
}
|
||||||
// READ
|
// READ
|
||||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||||
async getPullRequest(namespace, repo, mrNumber) {
|
async getPullRequest(namespace, repo, mrNumber, squash = true) {
|
||||||
const projectId = this.getProjectId(namespace, repo);
|
const projectId = this.getProjectId(namespace, repo);
|
||||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||||
return this.mapper.mapPullRequest(data);
|
const commits = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}/commits`);
|
||||||
|
// gitlab returns them in reverse order
|
||||||
|
commits.push(...data.map(c => c.id).reverse());
|
||||||
}
|
}
|
||||||
getPullRequestFromUrl(mrUrl) {
|
catch (error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for merge request n. ${mrNumber}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.mapper.mapPullRequest(data, commits);
|
||||||
|
}
|
||||||
|
getPullRequestFromUrl(mrUrl, squash = true) {
|
||||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||||
return this.getPullRequest(namespace, project, id);
|
return this.getPullRequest(namespace, project, id, squash);
|
||||||
}
|
}
|
||||||
// WRITE
|
// WRITE
|
||||||
async createPullRequest(backport) {
|
async createPullRequest(backport) {
|
||||||
|
@ -983,7 +1017,7 @@ class GitLabMapper {
|
||||||
return git_types_1.GitRepoState.LOCKED;
|
return git_types_1.GitRepoState.LOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async mapPullRequest(mr) {
|
async mapPullRequest(mr, commits) {
|
||||||
return {
|
return {
|
||||||
number: mr.iid,
|
number: mr.iid,
|
||||||
author: mr.author.username,
|
author: mr.author.username,
|
||||||
|
@ -999,11 +1033,15 @@ class GitLabMapper {
|
||||||
labels: mr.labels ?? [],
|
labels: mr.labels ?? [],
|
||||||
sourceRepo: await this.mapSourceRepo(mr),
|
sourceRepo: await this.mapSourceRepo(mr),
|
||||||
targetRepo: await this.mapTargetRepo(mr),
|
targetRepo: await this.mapTargetRepo(mr),
|
||||||
nCommits: 1,
|
// if commits list is provided use that as source
|
||||||
|
nCommits: (commits && commits.length > 1) ? commits.length : 1,
|
||||||
|
commits: (commits && commits.length > 1) ? commits : this.getSha(mr)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getSha(mr) {
|
||||||
// if mr is merged, use merge_commit_sha otherwise use sha
|
// if mr is merged, use merge_commit_sha otherwise use sha
|
||||||
// what is the difference between sha and diff_refs.head_sha?
|
// what is the difference between sha and diff_refs.head_sha?
|
||||||
commits: this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha] : [mr.sha]
|
return this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha] : [mr.sha];
|
||||||
};
|
|
||||||
}
|
}
|
||||||
async mapSourceRepo(mr) {
|
async mapSourceRepo(mr) {
|
||||||
const project = await this.getProject(mr.source_project_id);
|
const project = await this.getProject(mr.source_project_id);
|
||||||
|
|
71
dist/gha/index.js
vendored
71
dist/gha/index.js
vendored
|
@ -60,6 +60,7 @@ class ArgsParser {
|
||||||
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
||||||
labels: this.getOrDefault(args.labels, []),
|
labels: this.getOrDefault(args.labels, []),
|
||||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||||
|
squash: this.getOrDefault(args.squash, true),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +189,7 @@ class GHAArgsParser extends args_parser_1.default {
|
||||||
inheritReviewers: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-inherit-reviewers")),
|
inheritReviewers: !(0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("no-inherit-reviewers")),
|
||||||
labels: (0, args_utils_1.getAsCommaSeparatedList)((0, core_1.getInput)("labels")),
|
labels: (0, args_utils_1.getAsCommaSeparatedList)((0, core_1.getInput)("labels")),
|
||||||
inheritLabels: (0, args_utils_1.getAsBooleanOrDefault)((0, core_1.getInput)("inherit-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")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
@ -254,7 +256,7 @@ class PullRequestConfigsParser extends configs_parser_1.default {
|
||||||
async parse(args) {
|
async parse(args) {
|
||||||
let pr;
|
let pr;
|
||||||
try {
|
try {
|
||||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest);
|
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
this.logger.error("Something went wrong retrieving pull request");
|
this.logger.error("Something went wrong retrieving pull request");
|
||||||
|
@ -593,18 +595,33 @@ class GitHubClient {
|
||||||
getDefaultGitEmail() {
|
getDefaultGitEmail() {
|
||||||
return "noreply@github.com";
|
return "noreply@github.com";
|
||||||
}
|
}
|
||||||
async getPullRequest(owner, repo, prNumber) {
|
async getPullRequest(owner, repo, prNumber, squash = true) {
|
||||||
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
||||||
const { data } = await this.octokit.rest.pulls.get({
|
const { data } = await this.octokit.rest.pulls.get({
|
||||||
owner: owner,
|
owner: owner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
pull_number: prNumber
|
pull_number: prNumber,
|
||||||
});
|
});
|
||||||
return this.mapper.mapPullRequest(data);
|
const commits = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.octokit.rest.pulls.listCommits({
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
commits.push(...data.map(c => c.sha));
|
||||||
}
|
}
|
||||||
async getPullRequestFromUrl(prUrl) {
|
catch (error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for pull request n. ${prNumber}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.mapper.mapPullRequest(data, commits);
|
||||||
|
}
|
||||||
|
async getPullRequestFromUrl(prUrl, squash = true) {
|
||||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||||
return this.getPullRequest(owner, project, id);
|
return this.getPullRequest(owner, project, id, squash);
|
||||||
}
|
}
|
||||||
// WRITE
|
// WRITE
|
||||||
async createPullRequest(backport) {
|
async createPullRequest(backport) {
|
||||||
|
@ -698,7 +715,7 @@ class GitHubMapper {
|
||||||
return git_types_1.GitRepoState.CLOSED;
|
return git_types_1.GitRepoState.CLOSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async mapPullRequest(pr) {
|
async mapPullRequest(pr, commits) {
|
||||||
return {
|
return {
|
||||||
number: pr.number,
|
number: pr.number,
|
||||||
author: pr.user.login,
|
author: pr.user.login,
|
||||||
|
@ -715,10 +732,14 @@ class GitHubMapper {
|
||||||
sourceRepo: await this.mapSourceRepo(pr),
|
sourceRepo: await this.mapSourceRepo(pr),
|
||||||
targetRepo: await this.mapTargetRepo(pr),
|
targetRepo: await this.mapTargetRepo(pr),
|
||||||
nCommits: pr.commits,
|
nCommits: pr.commits,
|
||||||
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
// if commits is provided use them, otherwise fetch the single sha representing the whole pr
|
||||||
commits: pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha]
|
commits: (commits && commits.length > 0) ? commits : this.getSha(pr),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
getSha(pr) {
|
||||||
|
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
||||||
|
return pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha];
|
||||||
|
}
|
||||||
async mapSourceRepo(pr) {
|
async mapSourceRepo(pr) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
owner: pr.head.repo.full_name.split("/")[0],
|
owner: pr.head.repo.full_name.split("/")[0],
|
||||||
|
@ -809,14 +830,26 @@ class GitLabClient {
|
||||||
}
|
}
|
||||||
// READ
|
// READ
|
||||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||||
async getPullRequest(namespace, repo, mrNumber) {
|
async getPullRequest(namespace, repo, mrNumber, squash = true) {
|
||||||
const projectId = this.getProjectId(namespace, repo);
|
const projectId = this.getProjectId(namespace, repo);
|
||||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||||
return this.mapper.mapPullRequest(data);
|
const commits = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}/commits`);
|
||||||
|
// gitlab returns them in reverse order
|
||||||
|
commits.push(...data.map(c => c.id).reverse());
|
||||||
}
|
}
|
||||||
getPullRequestFromUrl(mrUrl) {
|
catch (error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for merge request n. ${mrNumber}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.mapper.mapPullRequest(data, commits);
|
||||||
|
}
|
||||||
|
getPullRequestFromUrl(mrUrl, squash = true) {
|
||||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||||
return this.getPullRequest(namespace, project, id);
|
return this.getPullRequest(namespace, project, id, squash);
|
||||||
}
|
}
|
||||||
// WRITE
|
// WRITE
|
||||||
async createPullRequest(backport) {
|
async createPullRequest(backport) {
|
||||||
|
@ -957,7 +990,7 @@ class GitLabMapper {
|
||||||
return git_types_1.GitRepoState.LOCKED;
|
return git_types_1.GitRepoState.LOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async mapPullRequest(mr) {
|
async mapPullRequest(mr, commits) {
|
||||||
return {
|
return {
|
||||||
number: mr.iid,
|
number: mr.iid,
|
||||||
author: mr.author.username,
|
author: mr.author.username,
|
||||||
|
@ -973,11 +1006,15 @@ class GitLabMapper {
|
||||||
labels: mr.labels ?? [],
|
labels: mr.labels ?? [],
|
||||||
sourceRepo: await this.mapSourceRepo(mr),
|
sourceRepo: await this.mapSourceRepo(mr),
|
||||||
targetRepo: await this.mapTargetRepo(mr),
|
targetRepo: await this.mapTargetRepo(mr),
|
||||||
nCommits: 1,
|
// if commits list is provided use that as source
|
||||||
|
nCommits: (commits && commits.length > 1) ? commits.length : 1,
|
||||||
|
commits: (commits && commits.length > 1) ? commits : this.getSha(mr)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getSha(mr) {
|
||||||
// if mr is merged, use merge_commit_sha otherwise use sha
|
// if mr is merged, use merge_commit_sha otherwise use sha
|
||||||
// what is the difference between sha and diff_refs.head_sha?
|
// what is the difference between sha and diff_refs.head_sha?
|
||||||
commits: this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha] : [mr.sha]
|
return this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha] : [mr.sha];
|
||||||
};
|
|
||||||
}
|
}
|
||||||
async mapSourceRepo(mr) {
|
async mapSourceRepo(mr) {
|
||||||
const project = await this.getProject(mr.source_project_id);
|
const project = await this.getProject(mr.source_project_id);
|
||||||
|
|
|
@ -38,6 +38,7 @@ export default abstract class ArgsParser {
|
||||||
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
inheritReviewers: this.getOrDefault(args.inheritReviewers, true),
|
||||||
labels: this.getOrDefault(args.labels, []),
|
labels: this.getOrDefault(args.labels, []),
|
||||||
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
inheritLabels: this.getOrDefault(args.inheritLabels, false),
|
||||||
|
squash: this.getOrDefault(args.squash, true),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,4 +18,5 @@ export interface Args {
|
||||||
inheritReviewers?: boolean, // if true and reviewers == [] then inherit reviewers from original pr
|
inheritReviewers?: boolean, // if true and reviewers == [] then inherit reviewers from original pr
|
||||||
labels?: string[], // backport pr labels
|
labels?: string[], // backport pr labels
|
||||||
inheritLabels?: boolean, // if true inherit labels from original pr
|
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
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ 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("--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("--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("--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("-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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ export default class CLIArgsParser extends ArgsParser {
|
||||||
inheritReviewers: opts.inheritReviewers,
|
inheritReviewers: opts.inheritReviewers,
|
||||||
labels: opts.labels,
|
labels: opts.labels,
|
||||||
inheritLabels: opts.inheritLabels,
|
inheritLabels: opts.inheritLabels,
|
||||||
|
squash: opts.squash,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ export default class GHAArgsParser extends ArgsParser {
|
||||||
inheritReviewers: !getAsBooleanOrDefault(getInput("no-inherit-reviewers")),
|
inheritReviewers: !getAsBooleanOrDefault(getInput("no-inherit-reviewers")),
|
||||||
labels: getAsCommaSeparatedList(getInput("labels")),
|
labels: getAsCommaSeparatedList(getInput("labels")),
|
||||||
inheritLabels: getAsBooleanOrDefault(getInput("inherit-labels")),
|
inheritLabels: getAsBooleanOrDefault(getInput("inherit-labels")),
|
||||||
|
squash: !getAsBooleanOrDefault(getInput("no-squash")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
public async parse(args: Args): Promise<Configs> {
|
public async parse(args: Args): Promise<Configs> {
|
||||||
let pr: GitPullRequest;
|
let pr: GitPullRequest;
|
||||||
try {
|
try {
|
||||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest);
|
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash!);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
this.logger.error("Something went wrong retrieving pull request");
|
this.logger.error("Something went wrong retrieving pull request");
|
||||||
throw error;
|
throw error;
|
||||||
|
|
|
@ -17,16 +17,18 @@ import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
||||||
* @param owner repository's owner
|
* @param owner repository's owner
|
||||||
* @param repo repository's name
|
* @param repo repository's name
|
||||||
* @param prNumber pull request number
|
* @param prNumber pull request number
|
||||||
|
* @param squash if true keep just one single commit, otherwise get the full list
|
||||||
* @returns {Promise<PullRequest>}
|
* @returns {Promise<PullRequest>}
|
||||||
*/
|
*/
|
||||||
getPullRequest(owner: string, repo: string, prNumber: number): Promise<GitPullRequest>;
|
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean): Promise<GitPullRequest>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pull request object from the underneath git service
|
* Get a pull request object from the underneath git service
|
||||||
* @param prUrl pull request html url
|
* @param prUrl pull request html url
|
||||||
|
* @param squash if true keep just one single commit, otherwise get the full list
|
||||||
* @returns {Promise<PullRequest>}
|
* @returns {Promise<PullRequest>}
|
||||||
*/
|
*/
|
||||||
getPullRequestFromUrl(prUrl: string): Promise<GitPullRequest>;
|
getPullRequestFromUrl(prUrl: string, squash: boolean): Promise<GitPullRequest>;
|
||||||
|
|
||||||
// WRITE
|
// WRITE
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ export default interface GitResponseMapper<PR, S> {
|
||||||
|
|
||||||
mapPullRequest(
|
mapPullRequest(
|
||||||
pr: PR,
|
pr: PR,
|
||||||
|
commits?: string[],
|
||||||
): Promise<GitPullRequest>;
|
): Promise<GitPullRequest>;
|
||||||
|
|
||||||
mapGitState(state: S): GitRepoState;
|
mapGitState(state: S): GitRepoState;
|
||||||
|
|
|
@ -31,20 +31,36 @@ export default class GitHubClient implements GitClient {
|
||||||
return "noreply@github.com";
|
return "noreply@github.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPullRequest(owner: string, repo: string, prNumber: number): Promise<GitPullRequest> {
|
async getPullRequest(owner: string, repo: string, prNumber: number, squash = true): Promise<GitPullRequest> {
|
||||||
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
this.logger.info(`Getting pull request ${owner}/${repo}/${prNumber}.`);
|
||||||
const { data } = await this.octokit.rest.pulls.get({
|
const { data } = await this.octokit.rest.pulls.get({
|
||||||
owner: owner,
|
owner: owner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
pull_number: prNumber
|
pull_number: prNumber,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.mapper.mapPullRequest(data as PullRequest);
|
const commits: string[] = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.octokit.rest.pulls.listCommits({
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
commits.push(...data.map(c => c.sha));
|
||||||
|
} catch(error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for pull request n. ${prNumber}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPullRequestFromUrl(prUrl: string): Promise<GitPullRequest> {
|
return this.mapper.mapPullRequest(data as PullRequest, commits);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPullRequestFromUrl(prUrl: string, squash = true): Promise<GitPullRequest> {
|
||||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||||
return this.getPullRequest(owner, project, id);
|
return this.getPullRequest(owner, project, id, squash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WRITE
|
// WRITE
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class GitHubMapper implements GitResponseMapper<PullRequest, "ope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async mapPullRequest(pr: PullRequest): Promise<GitPullRequest> {
|
async mapPullRequest(pr: PullRequest, commits?: string[]): Promise<GitPullRequest> {
|
||||||
return {
|
return {
|
||||||
number: pr.number,
|
number: pr.number,
|
||||||
author: pr.user.login,
|
author: pr.user.login,
|
||||||
|
@ -30,11 +30,16 @@ export default class GitHubMapper implements GitResponseMapper<PullRequest, "ope
|
||||||
sourceRepo: await this.mapSourceRepo(pr),
|
sourceRepo: await this.mapSourceRepo(pr),
|
||||||
targetRepo: await this.mapTargetRepo(pr),
|
targetRepo: await this.mapTargetRepo(pr),
|
||||||
nCommits: pr.commits,
|
nCommits: pr.commits,
|
||||||
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
// if commits is provided use them, otherwise fetch the single sha representing the whole pr
|
||||||
commits: pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha as string]
|
commits: (commits && commits.length > 0) ? commits : this.getSha(pr),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSha(pr: PullRequest) {
|
||||||
|
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
||||||
|
return pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha as string];
|
||||||
|
}
|
||||||
|
|
||||||
async mapSourceRepo(pr: PullRequest): Promise<GitRepository> {
|
async mapSourceRepo(pr: PullRequest): Promise<GitRepository> {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
owner: pr.head.repo.full_name.split("/")[0],
|
owner: pr.head.repo.full_name.split("/")[0],
|
||||||
|
|
|
@ -2,7 +2,7 @@ import LoggerService from "@bp/service/logger/logger-service";
|
||||||
import GitClient from "@bp/service/git/git-client";
|
import GitClient from "@bp/service/git/git-client";
|
||||||
import { GitPullRequest, BackportPullRequest } from "@bp/service/git/git.types";
|
import { GitPullRequest, BackportPullRequest } from "@bp/service/git/git.types";
|
||||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||||
import { MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
import { CommitSchema, MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
||||||
import GitLabMapper from "@bp/service/git/gitlab/gitlab-mapper";
|
import GitLabMapper from "@bp/service/git/gitlab/gitlab-mapper";
|
||||||
import axios, { Axios } from "axios";
|
import axios, { Axios } from "axios";
|
||||||
import https from "https";
|
import https from "https";
|
||||||
|
@ -41,16 +41,29 @@ export default class GitLabClient implements GitClient {
|
||||||
// READ
|
// READ
|
||||||
|
|
||||||
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
// example: <host>/api/v4/projects/<namespace>%2Fbackporting-example/merge_requests/1
|
||||||
async getPullRequest(namespace: string, repo: string, mrNumber: number): Promise<GitPullRequest> {
|
async getPullRequest(namespace: string, repo: string, mrNumber: number, squash = true): Promise<GitPullRequest> {
|
||||||
const projectId = this.getProjectId(namespace, repo);
|
const projectId = this.getProjectId(namespace, repo);
|
||||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||||
|
|
||||||
return this.mapper.mapPullRequest(data as MergeRequestSchema);
|
const commits: string[] = [];
|
||||||
|
if (!squash) {
|
||||||
|
// fetch all commits
|
||||||
|
try {
|
||||||
|
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}/commits`);
|
||||||
|
|
||||||
|
// gitlab returns them in reverse order
|
||||||
|
commits.push(...(data as CommitSchema[]).map(c => c.id).reverse());
|
||||||
|
} catch(error) {
|
||||||
|
throw new Error(`Failed to retrieve commits for merge request n. ${mrNumber}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPullRequestFromUrl(mrUrl: string): Promise<GitPullRequest> {
|
return this.mapper.mapPullRequest(data as MergeRequestSchema, commits);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPullRequestFromUrl(mrUrl: string, squash = true): Promise<GitPullRequest> {
|
||||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||||
return this.getPullRequest(namespace, project, id);
|
return this.getPullRequest(namespace, project, id, squash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WRITE
|
// WRITE
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default class GitLabMapper implements GitResponseMapper<MergeRequestSchem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async mapPullRequest(mr: MergeRequestSchema): Promise<GitPullRequest> {
|
async mapPullRequest(mr: MergeRequestSchema, commits?: string[]): Promise<GitPullRequest> {
|
||||||
return {
|
return {
|
||||||
number: mr.iid,
|
number: mr.iid,
|
||||||
author: mr.author.username,
|
author: mr.author.username,
|
||||||
|
@ -40,11 +40,16 @@ export default class GitLabMapper implements GitResponseMapper<MergeRequestSchem
|
||||||
labels: mr.labels ?? [],
|
labels: mr.labels ?? [],
|
||||||
sourceRepo: await this.mapSourceRepo(mr),
|
sourceRepo: await this.mapSourceRepo(mr),
|
||||||
targetRepo: await this.mapTargetRepo(mr),
|
targetRepo: await this.mapTargetRepo(mr),
|
||||||
nCommits: 1, // info not present on mr
|
// if commits list is provided use that as source
|
||||||
|
nCommits: (commits && commits.length > 1) ? commits.length : 1,
|
||||||
|
commits: (commits && commits.length > 1) ? commits : this.getSha(mr)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSha(mr: MergeRequestSchema) {
|
||||||
// if mr is merged, use merge_commit_sha otherwise use sha
|
// if mr is merged, use merge_commit_sha otherwise use sha
|
||||||
// what is the difference between sha and diff_refs.head_sha?
|
// what is the difference between sha and diff_refs.head_sha?
|
||||||
commits: this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha as string] : [mr.sha]
|
return this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha as string] : [mr.sha];
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async mapSourceRepo(mr: MergeRequestSchema): Promise<GitRepository> {
|
async mapSourceRepo(mr: MergeRequestSchema): Promise<GitRepository> {
|
||||||
|
|
|
@ -76,6 +76,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("with config file [default, short]", () => {
|
test("with config file [default, short]", () => {
|
||||||
|
@ -101,6 +102,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [default, long]", () => {
|
test("valid execution [default, long]", () => {
|
||||||
|
@ -128,6 +130,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("with config file [default, long]", () => {
|
test("with config file [default, long]", () => {
|
||||||
|
@ -153,6 +156,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, short]", () => {
|
test("valid execution [override, short]", () => {
|
||||||
|
@ -187,6 +191,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, long]", () => {
|
test("valid execution [override, long]", () => {
|
||||||
|
@ -237,6 +242,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(false);
|
expect(args.inheritReviewers).toEqual(false);
|
||||||
expectArrayEqual(args.labels!, ["cherry-pick :cherries:", "another spaced label"]);
|
expectArrayEqual(args.labels!, ["cherry-pick :cherries:", "another spaced label"]);
|
||||||
expect(args.inheritLabels).toEqual(true);
|
expect(args.inheritLabels).toEqual(true);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override using config file", () => {
|
test("override using config file", () => {
|
||||||
|
@ -262,6 +268,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
||||||
expect(args.inheritLabels).toEqual(true);
|
expect(args.inheritLabels).toEqual(true);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ignore custom option when config file is set", () => {
|
test("ignore custom option when config file is set", () => {
|
||||||
|
@ -314,5 +321,35 @@ describe("cli args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
||||||
expect(args.inheritLabels).toEqual(true);
|
expect(args.inheritLabels).toEqual(true);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("override squash to false", () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"--target-branch",
|
||||||
|
"target",
|
||||||
|
"--pull-request",
|
||||||
|
"https://localhost/whatever/pulls/1",
|
||||||
|
"--no-squash"
|
||||||
|
]);
|
||||||
|
|
||||||
|
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(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -48,10 +48,6 @@ describe("gha args parser", () => {
|
||||||
parser = new GHAArgsParser();
|
parser = new GHAArgsParser();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("valid execution [default]", () => {
|
test("valid execution [default]", () => {
|
||||||
spyGetInput({
|
spyGetInput({
|
||||||
"target-branch": "target",
|
"target-branch": "target",
|
||||||
|
@ -73,6 +69,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override]", () => {
|
test("valid execution [override]", () => {
|
||||||
|
@ -111,6 +108,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(false);
|
expect(args.inheritReviewers).toEqual(false);
|
||||||
expectArrayEqual(args.labels!, ["cherry-pick :cherries:", "another spaced label"]);
|
expectArrayEqual(args.labels!, ["cherry-pick :cherries:", "another spaced label"]);
|
||||||
expect(args.inheritLabels).toEqual(true);
|
expect(args.inheritLabels).toEqual(true);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("using config file", () => {
|
test("using config file", () => {
|
||||||
|
@ -135,6 +133,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expectArrayEqual(args.labels!, []);
|
expectArrayEqual(args.labels!, []);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ignore custom options when using config file", () => {
|
test("ignore custom options when using config file", () => {
|
||||||
|
@ -174,5 +173,31 @@ describe("gha args parser", () => {
|
||||||
expect(args.inheritReviewers).toEqual(true);
|
expect(args.inheritReviewers).toEqual(true);
|
||||||
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
expectArrayEqual(args.labels!, ["cherry-pick :cherries:"]);
|
||||||
expect(args.inheritLabels).toEqual(true);
|
expect(args.inheritLabels).toEqual(true);
|
||||||
|
expect(args.squash).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("override squash to false", () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://localhost/whatever/pulls/1",
|
||||||
|
"no-squash": "true",
|
||||||
|
});
|
||||||
|
|
||||||
|
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(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -5,8 +5,10 @@ import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||||
import { GitClientType } from "@bp/service/git/git.types";
|
import { GitClientType } from "@bp/service/git/git.types";
|
||||||
import { mockGitHubClient } from "../../../support/mock/git-client-mock-support";
|
import { mockGitHubClient } from "../../../support/mock/git-client-mock-support";
|
||||||
import { addProcessArgs, createTestFile, removeTestFile, resetProcessArgs } from "../../../support/utils";
|
import { addProcessArgs, createTestFile, removeTestFile, resetProcessArgs } from "../../../support/utils";
|
||||||
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner } from "../../../support/mock/github-data";
|
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner, multipleCommitsPullRequestFixture } from "../../../support/mock/github-data";
|
||||||
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
||||||
|
import GitHubMapper from "@bp/service/git/github/github-mapper";
|
||||||
|
import GitHubClient from "@bp/service/git/github/github-client";
|
||||||
|
|
||||||
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./github-pr-configs-parser-simple-pr-merged.json";
|
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./github-pr-configs-parser-simple-pr-merged.json";
|
||||||
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
|
const GITHUB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
|
||||||
|
@ -32,11 +34,15 @@ const GITHUB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT = {
|
||||||
"inheritLabels": true,
|
"inheritLabels": true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.spyOn(GitHubMapper.prototype, "mapPullRequest");
|
||||||
|
jest.spyOn(GitHubClient.prototype, "getPullRequest");
|
||||||
|
|
||||||
describe("github pull request config parser", () => {
|
describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const mergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`;
|
const mergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`;
|
||||||
const openPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${openPullRequestFixture.number}`;
|
const openPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${openPullRequestFixture.number}`;
|
||||||
const notMergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${notMergedPullRequestFixture.number}`;
|
const notMergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${notMergedPullRequestFixture.number}`;
|
||||||
|
const multipleCommitsPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${multipleCommitsPullRequestFixture.number}`;
|
||||||
|
|
||||||
let argsParser: CLIArgsParser;
|
let argsParser: CLIArgsParser;
|
||||||
let configParser: PullRequestConfigsParser;
|
let configParser: PullRequestConfigsParser;
|
||||||
|
@ -67,10 +73,6 @@ describe("github pull request config parser", () => {
|
||||||
configParser = new PullRequestConfigsParser();
|
configParser = new PullRequestConfigsParser();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("parse configs from pull request", async () => {
|
test("parse configs from pull request", async () => {
|
||||||
const args: Args = {
|
const args: Args = {
|
||||||
dryRun: false,
|
dryRun: false,
|
||||||
|
@ -86,6 +88,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "GitHub",
|
user: "GitHub",
|
||||||
|
@ -184,6 +191,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 4444, true);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
expect(configs.dryRun).toEqual(true);
|
expect(configs.dryRun).toEqual(true);
|
||||||
expect(configs.auth).toEqual("whatever");
|
expect(configs.auth).toEqual("whatever");
|
||||||
expect(configs.targetBranch).toEqual("prod");
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
@ -234,10 +246,9 @@ describe("github pull request config parser", () => {
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(async () => await configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test("override backport pr data inheriting reviewers", async () => {
|
test("override backport pr data inheriting reviewers", async () => {
|
||||||
const args: Args = {
|
const args: Args = {
|
||||||
dryRun: false,
|
dryRun: false,
|
||||||
|
@ -256,6 +267,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -332,6 +348,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -408,6 +429,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -486,6 +512,11 @@ describe("github pull request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -553,6 +584,11 @@ describe("github pull request config parser", () => {
|
||||||
const args: Args = argsParser.parse();
|
const args: Args = argsParser.parse();
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "GitHub",
|
user: "GitHub",
|
||||||
|
@ -619,6 +655,11 @@ describe("github pull request config parser", () => {
|
||||||
const args: Args = argsParser.parse();
|
const args: Args = argsParser.parse();
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -676,4 +717,82 @@ describe("github pull request config parser", () => {
|
||||||
bpBranchName: undefined,
|
bpBranchName: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("parse configs from pull request without squashing with multiple commits", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: multipleCommitsPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
gitUser: "GitHub",
|
||||||
|
gitEmail: "noreply@github.com",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: [],
|
||||||
|
inheritReviewers: true,
|
||||||
|
squash: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 8632, false);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "GitHub",
|
||||||
|
email: "noreply@github.com"
|
||||||
|
});
|
||||||
|
expect(configs.auth).toEqual("");
|
||||||
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||||
|
expect(configs.originalPullRequest).toEqual({
|
||||||
|
number: 8632,
|
||||||
|
author: "gh-user",
|
||||||
|
url: "https://api.github.com/repos/owner/reponame/pulls/8632",
|
||||||
|
htmlUrl: "https://github.com/owner/reponame/pull/8632",
|
||||||
|
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: [],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
nCommits: 2,
|
||||||
|
commits: ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]
|
||||||
|
});
|
||||||
|
expect(configs.backportPullRequest).toEqual({
|
||||||
|
author: "GitHub",
|
||||||
|
url: undefined,
|
||||||
|
htmlUrl: undefined,
|
||||||
|
title: "[prod] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/8632\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -7,6 +7,8 @@ import { getAxiosMocked } from "../../../support/mock/git-client-mock-support";
|
||||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR } from "../../../support/mock/gitlab-data";
|
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR } from "../../../support/mock/gitlab-data";
|
||||||
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
||||||
import { createTestFile, removeTestFile, spyGetInput } from "../../../support/utils";
|
import { createTestFile, removeTestFile, spyGetInput } from "../../../support/utils";
|
||||||
|
import GitLabClient from "@bp/service/git/gitlab/gitlab-client";
|
||||||
|
import GitLabMapper from "@bp/service/git/gitlab/gitlab-mapper";
|
||||||
|
|
||||||
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./gitlab-pr-configs-parser-simple-pr-merged.json";
|
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT_PATHNAME = "./gitlab-pr-configs-parser-simple-pr-merged.json";
|
||||||
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
|
const GITLAB_MERGED_PR_SIMPLE_CONFIG_FILE_CONTENT = {
|
||||||
|
@ -32,6 +34,8 @@ const GITLAB_MERGED_PR_COMPLEX_CONFIG_FILE_CONTENT = {
|
||||||
"inheritLabels": true,
|
"inheritLabels": true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.spyOn(GitLabMapper.prototype, "mapPullRequest");
|
||||||
|
jest.spyOn(GitLabClient.prototype, "getPullRequest");
|
||||||
|
|
||||||
jest.mock("axios", () => {
|
jest.mock("axios", () => {
|
||||||
return {
|
return {
|
||||||
|
@ -70,10 +74,6 @@ describe("gitlab merge request config parser", () => {
|
||||||
configParser = new PullRequestConfigsParser();
|
configParser = new PullRequestConfigsParser();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("parse configs from merge request", async () => {
|
test("parse configs from merge request", async () => {
|
||||||
const args: Args = {
|
const args: Args = {
|
||||||
dryRun: false,
|
dryRun: false,
|
||||||
|
@ -89,6 +89,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Gitlab",
|
user: "Gitlab",
|
||||||
|
@ -163,6 +168,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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(true);
|
expect(configs.dryRun).toEqual(true);
|
||||||
expect(configs.auth).toEqual("whatever");
|
expect(configs.auth).toEqual("whatever");
|
||||||
expect(configs.targetBranch).toEqual("prod");
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
@ -188,6 +198,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledWith("superuser", "backporting-example", 2, true);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
expect(configs.dryRun).toEqual(true);
|
expect(configs.dryRun).toEqual(true);
|
||||||
expect(configs.auth).toEqual("whatever");
|
expect(configs.auth).toEqual("whatever");
|
||||||
expect(configs.targetBranch).toEqual("prod");
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
@ -238,7 +253,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(async () => await configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => configParser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override backport pr data inheriting reviewers", async () => {
|
test("override backport pr data inheriting reviewers", async () => {
|
||||||
|
@ -259,6 +274,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -334,6 +354,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -409,6 +434,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -486,6 +516,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -551,6 +586,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
const args: Args = argsParser.parse();
|
const args: Args = argsParser.parse();
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Gitlab",
|
user: "Gitlab",
|
||||||
|
@ -616,6 +656,11 @@ describe("gitlab merge request config parser", () => {
|
||||||
const args: Args = argsParser.parse();
|
const args: Args = argsParser.parse();
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
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.dryRun).toEqual(false);
|
||||||
expect(configs.git).toEqual({
|
expect(configs.git).toEqual({
|
||||||
user: "Me",
|
user: "Me",
|
||||||
|
@ -672,4 +717,61 @@ describe("gitlab merge request config parser", () => {
|
||||||
bpBranchName: undefined,
|
bpBranchName: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("still open pull request without squash", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: true,
|
||||||
|
auth: "whatever",
|
||||||
|
pullRequest: openPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
gitUser: "Gitlab",
|
||||||
|
gitEmail: "noreply@gitlab.com",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: [],
|
||||||
|
inheritReviewers: true,
|
||||||
|
squash: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledWith("superuser", "backporting-example", 2, false);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["e4dd336a4a20f394df6665994df382fb1d193a11", "974519f65c9e0ed65277cd71026657a09fca05e7"]);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(true);
|
||||||
|
expect(configs.auth).toEqual("whatever");
|
||||||
|
expect(configs.targetBranch).toEqual("prod");
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "Gitlab",
|
||||||
|
email: "noreply@gitlab.com"
|
||||||
|
});
|
||||||
|
expect(configs.originalPullRequest).toEqual({
|
||||||
|
number: 2,
|
||||||
|
author: "superuser",
|
||||||
|
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||||
|
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||||
|
state: "open",
|
||||||
|
merged: false,
|
||||||
|
mergedBy: undefined,
|
||||||
|
title: "Update test.txt opened",
|
||||||
|
body: "Still opened mr body",
|
||||||
|
reviewers: ["superuser"],
|
||||||
|
assignees: ["superuser"],
|
||||||
|
labels: [],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "superuser",
|
||||||
|
project: "backporting-example",
|
||||||
|
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "superuser",
|
||||||
|
project: "backporting-example",
|
||||||
|
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||||
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
|
nCommits: 2,
|
||||||
|
commits: ["e4dd336a4a20f394df6665994df382fb1d193a11", "974519f65c9e0ed65277cd71026657a09fca05e7"]
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -30,10 +30,6 @@ describe("github service", () => {
|
||||||
gitClient = GitClientFactory.getOrCreate(GitClientType.GITLAB, "whatever", "apiUrl") as GitLabClient;
|
gitClient = GitClientFactory.getOrCreate(GitClientType.GITLAB, "whatever", "apiUrl") as GitLabClient;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("get merged pull request", async () => {
|
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);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ beforeEach(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
|
||||||
|
|
||||||
// reset process.env variables
|
// reset process.env variables
|
||||||
resetProcessArgs();
|
resetProcessArgs();
|
||||||
});
|
});
|
||||||
|
@ -292,7 +290,7 @@ describe("cli runner", () => {
|
||||||
"https://github.com/owner/reponame/pull/6666"
|
"https://github.com/owner/reponame/pull/6666"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("open pull request", async () => {
|
test("open pull request", async () => {
|
||||||
|
@ -636,4 +634,50 @@ describe("cli runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("multiple commits pr", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/8632",
|
||||||
|
"--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-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695");
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
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: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -68,8 +68,6 @@ beforeEach(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
|
||||||
|
|
||||||
// reset process.env variables
|
// reset process.env variables
|
||||||
resetProcessArgs();
|
resetProcessArgs();
|
||||||
});
|
});
|
||||||
|
@ -198,7 +196,7 @@ describe("cli runner", () => {
|
||||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("merged pull request", async () => {
|
test("merged pull request", async () => {
|
||||||
|
@ -501,4 +499,51 @@ describe("cli runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("multiple commits without squash", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||||
|
"--no-squash",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITLAB, undefined, "https://my.gitlab.host.com/api/v4");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://my.gitlab.host.com/superuser/backporting-example.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11");
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] Update test.txt opened",
|
||||||
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"),
|
||||||
|
reviewers: ["superuser"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -55,10 +55,6 @@ beforeEach(() => {
|
||||||
runner = new Runner(parser);
|
runner = new Runner(parser);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("gha runner", () => {
|
describe("gha runner", () => {
|
||||||
test("with dry run", async () => {
|
test("with dry run", async () => {
|
||||||
spyGetInput({
|
spyGetInput({
|
||||||
|
@ -139,7 +135,7 @@ describe("gha runner", () => {
|
||||||
"pull-request": "https://github.com/owner/reponame/pull/6666"
|
"pull-request": "https://github.com/owner/reponame/pull/6666"
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("open pull request", async () => {
|
test("open pull request", async () => {
|
||||||
|
@ -460,4 +456,47 @@ describe("gha runner", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("multiple commits pr", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://api.github.com/repos/owner/reponame/pulls/8632",
|
||||||
|
"no-squash": "true",
|
||||||
|
});
|
||||||
|
|
||||||
|
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-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695");
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-0404fb922ab75c3a8aecad5c97d9af388df04695-11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
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: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -66,10 +66,6 @@ beforeEach(() => {
|
||||||
runner = new Runner(parser);
|
runner = new Runner(parser);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("gha runner", () => {
|
describe("gha runner", () => {
|
||||||
test("with dry run", async () => {
|
test("with dry run", async () => {
|
||||||
spyGetInput({
|
spyGetInput({
|
||||||
|
@ -150,7 +146,7 @@ describe("gha runner", () => {
|
||||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
await expect(() => runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("merged pull request", async () => {
|
test("merged pull request", async () => {
|
||||||
|
@ -423,4 +419,49 @@ describe("gha runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("multiple commits without squash", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||||
|
"no-squash": "true",
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITLAB, undefined, "https://my.gitlab.host.com/api/v4");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://my.gitlab.host.com/superuser/backporting-example.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11");
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7");
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-target-e4dd336a4a20f394df6665994df382fb1d193a11-974519f65c9e0ed65277cd71026657a09fca05e7",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] Update test.txt opened",
|
||||||
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"),
|
||||||
|
reviewers: ["superuser"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -1,7 +1,7 @@
|
||||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||||
import { Moctokit } from "@kie/mock-github";
|
import { Moctokit } from "@kie/mock-github";
|
||||||
import { targetOwner, repo, mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, notFoundPullRequestNumber, sameOwnerPullRequestFixture } from "./github-data";
|
import { targetOwner, repo, mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, notFoundPullRequestNumber, multipleCommitsPullRequestFixture, multipleCommitsPullRequestCommits } from "./github-data";
|
||||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR, PROJECT_EXAMPLE, SUPERUSER} from "./gitlab-data";
|
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR, OPEN_PR_COMMITS, PROJECT_EXAMPLE, SUPERUSER} from "./gitlab-data";
|
||||||
|
|
||||||
const logger = LoggerServiceFactory.getLogger();
|
const logger = LoggerServiceFactory.getLogger();
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ export const getAxiosMocked = (url: string) => {
|
||||||
data = PROJECT_EXAMPLE;
|
data = PROJECT_EXAMPLE;
|
||||||
} else if (url.endsWith("users?username=superuser")) {
|
} else if (url.endsWith("users?username=superuser")) {
|
||||||
data = [SUPERUSER];
|
data = [SUPERUSER];
|
||||||
|
} else if (url.endsWith("merge_requests/2/commits")) {
|
||||||
|
data = OPEN_PR_COMMITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -99,11 +101,11 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
.get({
|
.get({
|
||||||
owner: targetOwner,
|
owner: targetOwner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
pull_number: sameOwnerPullRequestFixture.number
|
pull_number: multipleCommitsPullRequestFixture.number
|
||||||
})
|
})
|
||||||
.reply({
|
.reply({
|
||||||
status: 200,
|
status: 200,
|
||||||
data: sameOwnerPullRequestFixture
|
data: multipleCommitsPullRequestFixture
|
||||||
});
|
});
|
||||||
|
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
|
@ -128,6 +130,17 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
data: notMergedPullRequestFixture
|
data: notMergedPullRequestFixture
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.listCommits({
|
||||||
|
owner: targetOwner,
|
||||||
|
repo: repo,
|
||||||
|
pull_number: multipleCommitsPullRequestFixture.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: multipleCommitsPullRequestCommits
|
||||||
|
});
|
||||||
|
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
.create()
|
.create()
|
||||||
.reply({
|
.reply({
|
||||||
|
@ -156,7 +169,6 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
data: {}
|
data: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// invalid requests
|
// invalid requests
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
.get({
|
.get({
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ export const notMergedPullRequestFixture = {
|
||||||
"changed_files": 2
|
"changed_files": 2
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sameOwnerPullRequestFixture = {
|
export const multipleCommitsPullRequestFixture = {
|
||||||
"url": "https://api.github.com/repos/owner/reponame/pulls/8632",
|
"url": "https://api.github.com/repos/owner/reponame/pulls/8632",
|
||||||
"id": 1137188271,
|
"id": 1137188271,
|
||||||
"node_id": "PR_kwDOABTq6s5DyB2v",
|
"node_id": "PR_kwDOABTq6s5DyB2v",
|
||||||
|
@ -1803,3 +1803,164 @@ export const sameOwnerPullRequestFixture = {
|
||||||
"deletions": 2,
|
"deletions": 2,
|
||||||
"changed_files": 2
|
"changed_files": 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const multipleCommitsPullRequestCommits = [
|
||||||
|
{
|
||||||
|
"sha": "0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"node_id": "C_kwDOImgs99oAKDA0MDRmYjkyMmFiNzVjM2E4YWVjYWQ1Yzk3ZDlhZjM4OGRmMDQ2OTU",
|
||||||
|
"commit": {
|
||||||
|
"author": {
|
||||||
|
"name": "owner",
|
||||||
|
"email": "owner@email.com",
|
||||||
|
"date": "2023-07-06T13:46:30Z"
|
||||||
|
},
|
||||||
|
"committer": {
|
||||||
|
"name": "GitHub",
|
||||||
|
"email": "noreply@github.com",
|
||||||
|
"date": "2023-07-06T13:46:30Z"
|
||||||
|
},
|
||||||
|
"message": "Update file1.txt",
|
||||||
|
"tree": {
|
||||||
|
"sha": "50be1d7031b02a2ae609f432f2a1e0f818d827b2",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/git/trees/50be1d7031b02a2ae609f432f2a1e0f818d827b2"
|
||||||
|
},
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/git/commits/0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"comment_count": 0,
|
||||||
|
"verification": {
|
||||||
|
"verified": true,
|
||||||
|
"reason": "valid",
|
||||||
|
"signature": "-----BEGIN PGP SIGNATURE-----\n\nno-signature=\n=fivd\n-----END PGP SIGNATURE-----\n",
|
||||||
|
"payload": "tree 50be1d7031b02a2ae609f432f2a1e0f818d827b2\nparent c85b8fcdb741814b3e90e6e5729455cf46ff26ea\nauthor Owner <owner@email.com> 1688651190 +0200\ncommitter GitHub <noreply@github.com> 1688651190 +0200\n\nUpdate file1.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/commits/0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"html_url": "https://github.com/owner/reponame/commit/0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"comments_url": "https://api.github.com/repos/owner/reponame/commits/0404fb922ab75c3a8aecad5c97d9af388df04695/comments",
|
||||||
|
"author": {
|
||||||
|
"login": "owner",
|
||||||
|
"id": 26715795,
|
||||||
|
"node_id": "MDQ6VXNlcjI2NzE1Nzk1",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/26715795?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/owner",
|
||||||
|
"html_url": "https://github.com/owner",
|
||||||
|
"followers_url": "https://api.github.com/users/owner/followers",
|
||||||
|
"following_url": "https://api.github.com/users/owner/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/owner/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/owner/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/owner/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/owner/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/owner/repos",
|
||||||
|
"events_url": "https://api.github.com/users/owner/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/owner/received_events",
|
||||||
|
"type": "User",
|
||||||
|
"site_admin": false
|
||||||
|
},
|
||||||
|
"committer": {
|
||||||
|
"login": "web-flow",
|
||||||
|
"id": 19864447,
|
||||||
|
"node_id": "MDQ6VXNlcjE5ODY0NDQ3",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/19864447?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/web-flow",
|
||||||
|
"html_url": "https://github.com/web-flow",
|
||||||
|
"followers_url": "https://api.github.com/users/web-flow/followers",
|
||||||
|
"following_url": "https://api.github.com/users/web-flow/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/web-flow/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/web-flow/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/web-flow/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/web-flow/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/web-flow/repos",
|
||||||
|
"events_url": "https://api.github.com/users/web-flow/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/web-flow/received_events",
|
||||||
|
"type": "User",
|
||||||
|
"site_admin": false
|
||||||
|
},
|
||||||
|
"parents": [
|
||||||
|
{
|
||||||
|
"sha": "c85b8fcdb741814b3e90e6e5729455cf46ff26ea",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/commits/c85b8fcdb741814b3e90e6e5729455cf46ff26ea",
|
||||||
|
"html_url": "https://github.com/owner/reponame/commit/c85b8fcdb741814b3e90e6e5729455cf46ff26ea"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sha": "11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
"node_id": "C_kwDOImgs99oAKDExZGE0ZTM4YWEzZTU3N2ZmZGU2ZDU0NmYxYzUyZTUzYjA0ZDMxNTE",
|
||||||
|
"commit": {
|
||||||
|
"author": {
|
||||||
|
"name": "Owner",
|
||||||
|
"email": "owner@email.com",
|
||||||
|
"date": "2023-07-10T13:23:44Z"
|
||||||
|
},
|
||||||
|
"committer": {
|
||||||
|
"name": "GitHub",
|
||||||
|
"email": "noreply@github.com",
|
||||||
|
"date": "2023-07-10T13:23:44Z"
|
||||||
|
},
|
||||||
|
"message": "Update file2.txt",
|
||||||
|
"tree": {
|
||||||
|
"sha": "fdd16fb791eef26fd84c3bfa34fd89eb1f7a85be",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/git/trees/fdd16fb791eef26fd84c3bfa34fd89eb1f7a85be"
|
||||||
|
},
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/git/commits/11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
"comment_count": 0,
|
||||||
|
"verification": {
|
||||||
|
"verified": true,
|
||||||
|
"reason": "valid",
|
||||||
|
"signature": "-----BEGIN PGP SIGNATURE-----\n\nno-signature\n=//hm\n-----END PGP SIGNATURE-----\n",
|
||||||
|
"payload": "tree fdd16fb791eef26fd84c3bfa34fd89eb1f7a85be\nparent 0404fb922ab75c3a8aecad5c97d9af388df04695\nauthor Owner <owner@email.com> 1688995424 +0200\ncommitter GitHub <noreply@github.com> 1688995424 +0200\n\nUpdate file2.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/commits/11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
"html_url": "https://github.com/owner/reponame/commit/11da4e38aa3e577ffde6d546f1c52e53b04d3151",
|
||||||
|
"comments_url": "https://api.github.com/repos/owner/reponame/commits/11da4e38aa3e577ffde6d546f1c52e53b04d3151/comments",
|
||||||
|
"author": {
|
||||||
|
"login": "owner",
|
||||||
|
"id": 26715795,
|
||||||
|
"node_id": "MDQ6VXNlcjI2NzE1Nzk1",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/26715795?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/owner",
|
||||||
|
"html_url": "https://github.com/owner",
|
||||||
|
"followers_url": "https://api.github.com/users/owner/followers",
|
||||||
|
"following_url": "https://api.github.com/users/owner/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/owner/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/owner/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/owner/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/owner/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/owner/repos",
|
||||||
|
"events_url": "https://api.github.com/users/owner/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/owner/received_events",
|
||||||
|
"type": "User",
|
||||||
|
"site_admin": false
|
||||||
|
},
|
||||||
|
"committer": {
|
||||||
|
"login": "web-flow",
|
||||||
|
"id": 19864447,
|
||||||
|
"node_id": "MDQ6VXNlcjE5ODY0NDQ3",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/19864447?v=4",
|
||||||
|
"gravatar_id": "",
|
||||||
|
"url": "https://api.github.com/users/web-flow",
|
||||||
|
"html_url": "https://github.com/web-flow",
|
||||||
|
"followers_url": "https://api.github.com/users/web-flow/followers",
|
||||||
|
"following_url": "https://api.github.com/users/web-flow/following{/other_user}",
|
||||||
|
"gists_url": "https://api.github.com/users/web-flow/gists{/gist_id}",
|
||||||
|
"starred_url": "https://api.github.com/users/web-flow/starred{/owner}{/repo}",
|
||||||
|
"subscriptions_url": "https://api.github.com/users/web-flow/subscriptions",
|
||||||
|
"organizations_url": "https://api.github.com/users/web-flow/orgs",
|
||||||
|
"repos_url": "https://api.github.com/users/web-flow/repos",
|
||||||
|
"events_url": "https://api.github.com/users/web-flow/events{/privacy}",
|
||||||
|
"received_events_url": "https://api.github.com/users/web-flow/received_events",
|
||||||
|
"type": "User",
|
||||||
|
"site_admin": false
|
||||||
|
},
|
||||||
|
"parents": [
|
||||||
|
{
|
||||||
|
"sha": "0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/commits/0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
"html_url": "https://github.com/owner/reponame/commit/0404fb922ab75c3a8aecad5c97d9af388df04695"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
|
@ -529,6 +529,49 @@ export const CLOSED_NOT_MERGED_MR = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const OPEN_PR_COMMITS = [
|
||||||
|
{
|
||||||
|
"id":"974519f65c9e0ed65277cd71026657a09fca05e7",
|
||||||
|
"short_id":"974519f6",
|
||||||
|
"created_at":"2023-07-10T19:23:04.000Z",
|
||||||
|
"parent_ids":[
|
||||||
|
|
||||||
|
],
|
||||||
|
"title":"Add another file",
|
||||||
|
"message":"Add another file",
|
||||||
|
"author_name":"Super User",
|
||||||
|
"author_email":"superuser@email.com",
|
||||||
|
"authored_date":"2023-07-10T19:23:04.000Z",
|
||||||
|
"committer_name":"Super User",
|
||||||
|
"committer_email":"superuser@email.com",
|
||||||
|
"committed_date":"2023-07-10T19:23:04.000Z",
|
||||||
|
"trailers":{
|
||||||
|
|
||||||
|
},
|
||||||
|
"web_url":"https://gitlab.com/superuser/backporting-example/-/commit/974519f65c9e0ed65277cd71026657a09fca05e7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":"e4dd336a4a20f394df6665994df382fb1d193a11",
|
||||||
|
"short_id":"e4dd336a",
|
||||||
|
"created_at":"2023-06-29T09:59:10.000Z",
|
||||||
|
"parent_ids":[
|
||||||
|
|
||||||
|
],
|
||||||
|
"title":"Add new file",
|
||||||
|
"message":"Add new file",
|
||||||
|
"author_name":"Super User",
|
||||||
|
"author_email":"superuser@email.com",
|
||||||
|
"authored_date":"2023-06-29T09:59:10.000Z",
|
||||||
|
"committer_name":"Super User",
|
||||||
|
"committer_email":"superuser@email.com",
|
||||||
|
"committed_date":"2023-06-29T09:59:10.000Z",
|
||||||
|
"trailers":{
|
||||||
|
|
||||||
|
},
|
||||||
|
"web_url":"https://gitlab.com/superuser/backporting-example/-/commit/e4dd336a4a20f394df6665994df382fb1d193a11"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export const SUPERUSER = {
|
export const SUPERUSER = {
|
||||||
"id":14041,
|
"id":14041,
|
||||||
"username":"superuser",
|
"username":"superuser",
|
||||||
|
|
Loading…
Add table
Reference in a new issue