mirror of
https://github.com/kiegroup/git-backporting.git
synced 2025-04-21 19:18:43 +00:00
Compare commits
31 commits
Author | SHA1 | Date | |
---|---|---|---|
|
7ff4fce545 | ||
|
c9a7375bf9 | ||
|
d74a787035 | ||
|
3a9d367b48 | ||
|
b9ed3ac959 | ||
|
3deee59d4c | ||
|
2b4b429356 | ||
|
31eabaf84a | ||
|
a14014e89e | ||
|
b4d0481c56 | ||
|
c3daf80306 | ||
|
6d6592f958 | ||
|
e2d73d050c | ||
|
1e8358bb2c | ||
|
fe22142b85 | ||
|
26a4c5dfd2 | ||
|
c5d7f0ea56 | ||
|
cb3473d7c9 | ||
|
da6431b114 | ||
|
c22286f85e | ||
|
2bb7f73112 | ||
|
6042bcc40b | ||
|
fc5dba6703 | ||
|
e6f86f8f83 | ||
|
0a07bf30c8 | ||
|
6d9b9db590 | ||
|
fe6be83074 | ||
|
53cc505f17 | ||
|
b2e2e271b9 | ||
|
ee7a87f26f | ||
|
b30ba6021a |
51 changed files with 11617 additions and 6703 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -19,9 +19,9 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Node ${{ matrix.node-version }}
|
- name: Setup Node ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
|
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: ArtiomTr/jest-coverage-report-action@v2
|
- uses: ArtiomTr/jest-coverage-report-action@v2
|
||||||
with:
|
with:
|
||||||
test-script: npm test
|
test-script: npm test
|
4
.github/workflows/prepare-release.yml
vendored
4
.github/workflows/prepare-release.yml
vendored
|
@ -19,11 +19,11 @@ jobs:
|
||||||
name: Prepare release
|
name: Prepare release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: Git config
|
- name: Git config
|
||||||
|
|
4
.github/workflows/pull-request.yml
vendored
4
.github/workflows/pull-request.yml
vendored
|
@ -24,9 +24,9 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Node ${{ matrix.node-version }}
|
- name: Setup Node ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
@ -17,11 +17,11 @@ jobs:
|
||||||
name: Release package
|
name: Release package
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
- name: Git config
|
- name: Git config
|
||||||
|
|
63
CHANGELOG.md
63
CHANGELOG.md
|
@ -1,5 +1,68 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## <small>4.8.5 (2025-04-15)</small>
|
||||||
|
|
||||||
|
* build(deps): audit fix (#150) ([3a9d367](https://github.com/kiegroup/git-backporting/commit/3a9d367)), closes [#150](https://github.com/kiegroup/git-backporting/issues/150)
|
||||||
|
* build(deps): upgrade release-it to v18 (#153) ([c9a7375](https://github.com/kiegroup/git-backporting/commit/c9a7375)), closes [#153](https://github.com/kiegroup/git-backporting/issues/153)
|
||||||
|
* fix(#151): fix gitlab post comments url (#152) ([d74a787](https://github.com/kiegroup/git-backporting/commit/d74a787)), closes [#152](https://github.com/kiegroup/git-backporting/issues/152)
|
||||||
|
|
||||||
|
## [4.8.4](https://github.com/kiegroup/git-backporting/compare/v4.8.3...v4.8.4) (2024-11-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* abort conflicting cherry-pick before starting new one ([#146](https://github.com/kiegroup/git-backporting/issues/146)) ([3deee59](https://github.com/kiegroup/git-backporting/commit/3deee59d4c3b726ae131b5974af4618dd5e7d1d2))
|
||||||
|
|
||||||
|
## [4.8.3](https://github.com/kiegroup/git-backporting/compare/v4.8.2...v4.8.3) (2024-10-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* auto-no-squash inference for GitLab ([#140](https://github.com/kiegroup/git-backporting/issues/140)) ([b4d0481](https://github.com/kiegroup/git-backporting/commit/b4d0481c5649115367f1ae0724d12d55b6b86e10))
|
||||||
|
|
||||||
|
## [4.8.2](https://github.com/kiegroup/git-backporting/compare/v4.8.1...v4.8.2) (2024-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* cherry-pick order on GitLab by reversing commmit list only once ([#137](https://github.com/kiegroup/git-backporting/issues/137)) ([e2d73d0](https://github.com/kiegroup/git-backporting/commit/e2d73d050c8387c0858877ac3c56c565bacaf4f9))
|
||||||
|
* handle Codeberg returning null entry in requested_reviewers ([#136](https://github.com/kiegroup/git-backporting/issues/136)) ([1e8358b](https://github.com/kiegroup/git-backporting/commit/1e8358bb2c461c56cf86e82bec4d71284866b13b))
|
||||||
|
|
||||||
|
## [4.8.1](https://github.com/kiegroup/git-backporting/compare/v4.8.0...v4.8.1) (2024-07-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **gh130:** apply commits in the correct order on github ([#131](https://github.com/kiegroup/git-backporting/issues/131)) ([cb3473d](https://github.com/kiegroup/git-backporting/commit/cb3473d7c9de66cb7bec188f08538e134cdc4bc0))
|
||||||
|
|
||||||
|
## [4.8.0](https://github.com/kiegroup/git-backporting/compare/v4.7.1...v4.8.0) (2024-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* auto-detect the value of the no-squash option ([#118](https://github.com/kiegroup/git-backporting/issues/118)) ([6042bcc](https://github.com/kiegroup/git-backporting/commit/6042bcc40ba83593a23dfe4d92cf50655a05b1cd))
|
||||||
|
* implement error notification as pr comment ([#124](https://github.com/kiegroup/git-backporting/issues/124)) ([2bb7f73](https://github.com/kiegroup/git-backporting/commit/2bb7f731127e099d1f196e6785e992589f7c4940))
|
||||||
|
|
||||||
|
## [4.7.1](https://github.com/kiegroup/git-backporting/compare/v4.7.0...v4.7.1) (2024-04-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* gha input is target-branch-pattern, not target-reg-exp ([#120](https://github.com/kiegroup/git-backporting/issues/120)) ([e6f86f8](https://github.com/kiegroup/git-backporting/commit/e6f86f8f839bc86adf36fa0d3c8dcad6cab2f92e))
|
||||||
|
|
||||||
|
## [4.7.0](https://github.com/kiegroup/git-backporting/compare/v4.6.0...v4.7.0) (2024-04-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add --cherry-pick-options to add to all cherry-pick run ([#116](https://github.com/kiegroup/git-backporting/issues/116)) ([fe6be83](https://github.com/kiegroup/git-backporting/commit/fe6be83074476d91c1b038fd7f03c4868e96f113))
|
||||||
|
* **gh75:** extract target branched from pr labels ([#112](https://github.com/kiegroup/git-backporting/issues/112)) ([53cc505](https://github.com/kiegroup/git-backporting/commit/53cc505f17630fb30daa70f75895323325cc0c7d))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* return GitHub no-squash commits in order ([#115](https://github.com/kiegroup/git-backporting/issues/115)) ([6d9b9db](https://github.com/kiegroup/git-backporting/commit/6d9b9db590f9713e2b056bcc8e20fc3f3c70618b))
|
||||||
|
|
||||||
## [4.6.0](https://github.com/kiegroup/git-backporting/compare/v4.5.2...v4.6.0) (2024-03-25)
|
## [4.6.0](https://github.com/kiegroup/git-backporting/compare/v4.5.2...v4.6.0) (2024-03-25)
|
||||||
|
|
||||||
|
|
||||||
|
|
50
README.md
50
README.md
|
@ -24,7 +24,6 @@ Table of content
|
||||||
* **[CLI tool](#cli-tool)**
|
* **[CLI tool](#cli-tool)**
|
||||||
* **[GitHub action](#github-action)**
|
* **[GitHub action](#github-action)**
|
||||||
* **[Future works](#future-works)**
|
* **[Future works](#future-works)**
|
||||||
* **[Migrating to v4](#migrating-to-v4)**
|
|
||||||
* **[Development](#development)**
|
* **[Development](#development)**
|
||||||
* **[Contributing](#contributing)**
|
* **[Contributing](#contributing)**
|
||||||
* **[License](#license)**
|
* **[License](#license)**
|
||||||
|
@ -39,7 +38,7 @@ Therefore this tools is for anybody who is working on projects where they have t
|
||||||
|
|
||||||
## CLI tool
|
## CLI tool
|
||||||
|
|
||||||
> All instructions provided below pertain to version `v4` of the tool. If you wish to use an earlier version, we strongly encourage you to consider migrating to version `v4` as there are no valid reason to keep using older versions. Please refer to [Migrating to v4](#migrating-to-v4) section for comprehensive details on how to properly migrate to version `v4`.
|
> All instructions provided below pertain to version `v4` of the tool. If you wish to use an earlier version, please refer to the documentation from the corresponding tag/release.
|
||||||
|
|
||||||
This tool is released on the [public npm registry](https://www.npmjs.com/), therefore it can be easily installed using `npm`:
|
This tool is released on the [public npm registry](https://www.npmjs.com/), therefore it can be easily installed using `npm`:
|
||||||
|
|
||||||
|
@ -71,18 +70,34 @@ It works in this way: given the provided `pull/merge request` it infers the serv
|
||||||
|
|
||||||
After that it clones the corresponding git repository, check out in the provided `target branch` and create a new branch from that (name automatically generated if not provided as option).
|
After that it clones the corresponding git repository, check out in the provided `target branch` and create a new branch from that (name automatically generated if not provided as option).
|
||||||
|
|
||||||
By default the tool will try to cherry-pick the single squashed/merged commit into the newly created branch (please consider using `--no-squash` option if you want to cherry-pick all commits belonging to the provided pull request).
|
By default the tool will try to cherry-pick the single squashed/merged commit into the newly created branch. The `--no-squash` and `--auto-no-squash` options control this behavior according the following table.
|
||||||
|
|
||||||
|
| No squash | Auto no squash |Behavior|
|
||||||
|
|---|---|---|
|
||||||
|
| unset/false | unset/false | cherry-pick a single commit, squashed or merged |
|
||||||
|
| set/true | unset/false | cherry-pick all commits found in the the original pull/merge request|
|
||||||
|
| (ignored) | set/true | cherry-pick all commits if the original pull/merge request was merged, a single commit if it was squashed |
|
||||||
|
|
||||||
Based on the original pull request, creates a new one containing the backporting to the target branch. Note that most of these information can be overridden with appropriate CLI options or GHA inputs.
|
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.
|
||||||
|
|
||||||
#### Default cherry-pick strategy
|
#### cherry-pick strategy
|
||||||
|
|
||||||
The default cherry-pick strategy is `recursive` with `theirs` option for automatic conflicts resolution. Therefore, by default, all commits are cherry-picked using the following git-equivalent command:
|
The default cherry-pick strategy is `recursive` with `theirs` option for automatic conflicts resolution. Therefore, by default, all commits are cherry-picked using the following git-equivalent command:
|
||||||
```bash
|
```bash
|
||||||
$ git cherry-pick -m 1 --strategy=recursive --strategy-option=theirs <sha>
|
$ git cherry-pick -m 1 --strategy=recursive --strategy-option=theirs <sha>
|
||||||
```
|
```
|
||||||
|
|
||||||
From version `v4.2.0` we made both `strategy` and `strategy-option` fully configurable from CLI or GitHub action, so if users need a specific strategy which differs from the default one please consider using either `--strategy` or `--strategy-option`, or their equivalent GitHub action inputs, more details in [inputs](#inputs) section.
|
From version `v4.2.0` both can be configured via the `strategy` or `strategy-option` inputs if using the action and the `--strategy` or `--strategy-option` arguments if using the CLI.
|
||||||
|
|
||||||
|
The [default strategy](https://git-scm.com/docs/git-merge#Documentation/git-merge.txt--sltstrategygt) of the `git-cherry-pick` command is different from the defaults of `git-backporting`.
|
||||||
|
```bash
|
||||||
|
$ git cherry-pick -m 1 <sha>
|
||||||
|
```
|
||||||
|
is the same as:
|
||||||
|
```bash
|
||||||
|
$ git cherry-pick -m 1 --strategy=ort --strategy-option=find-renames <sha>
|
||||||
|
```
|
||||||
|
If there is a conflict the backport will fail and require manual intervention.
|
||||||
|
|
||||||
> **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).
|
> **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).
|
||||||
|
|
||||||
|
@ -95,6 +110,7 @@ This tool comes with some inputs that allow users to override the default behavi
|
||||||
| Version | -V, --version | - | Current version of the tool | |
|
| Version | -V, --version | - | Current version of the tool | |
|
||||||
| Help | -h, --help | - | Display the help message | |
|
| Help | -h, --help | - | Display the help message | |
|
||||||
| Target Branches | -tb, --target-branch | N | Comma separated list of branches where the changes must be backported to | |
|
| Target Branches | -tb, --target-branch | N | Comma separated list of branches where the changes must be backported to | |
|
||||||
|
| Target Branches Pattern | -tbp, --target-branch-pattern | N | Regular expression pattern to extract target branch(es) from pr labels. The branches will be extracted from the pattern's required `target` named capturing group, e.g., `^backport (?<target>([^ ]+))$` | |
|
||||||
| Pull Request | -pr, --pull-request | N | Original pull request url, the one that must be backported, e.g., https://github.com/kiegroup/git-backporting/pull/1 | |
|
| Pull Request | -pr, --pull-request | N | Original pull request url, the one that must be backported, e.g., https://github.com/kiegroup/git-backporting/pull/1 | |
|
||||||
| Configuration File | -cf, --config-file | N | Configuration file, in JSON format, containing all options to be overridded, note that if provided all other CLI options will be ignored | |
|
| Configuration File | -cf, --config-file | N | Configuration file, in JSON format, containing all options to be overridded, note that if provided all other CLI options will be ignored | |
|
||||||
| Auth | -a, --auth | N | Git access/authorization token, if provided all token env variables will be ignored. See [auth token](#authorization-token) section for more details | "" |
|
| Auth | -a, --auth | N | Git access/authorization token, if provided all token env variables will be ignored. See [auth token](#authorization-token) section for more details | "" |
|
||||||
|
@ -111,13 +127,16 @@ This tool comes with some inputs that allow users to override the default behavi
|
||||||
| Backport Branch Names | --bp-branch-name | N | Comma separated lists of the backporting pull request branch names, if they exceeds 250 chars they will be truncated | bp-{target-branch}-{sha1}...{shaN} |
|
| Backport Branch Names | --bp-branch-name | N | Comma separated lists of the backporting pull request branch names, if they exceeds 250 chars they will be truncated | bp-{target-branch}-{sha1}...{shaN} |
|
||||||
| Labels | --labels | N | Provide custom labels to be added to the backporting pull request | [] |
|
| 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 |
|
| No squash | --no-squash | N | Backport all commits found in the pull request. The default behavior is to only backport the first commit that was merged in the base branch. | |
|
||||||
|
| Auto no squash | --auto-no-squash | N | If the pull request was merged or is open, backport all commits. If the pull request commits were squashed, backport the squashed commit. | |
|
||||||
| Strategy | --strategy | N | Cherry pick merging strategy, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "recursive" |
|
| Strategy | --strategy | N | Cherry pick merging strategy, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "recursive" |
|
||||||
| Strategy Option | --strategy-option | N | Cherry pick merging strategy option, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "theirs" |
|
| Strategy Option | --strategy-option | N | Cherry pick merging strategy option, see [git-merge](https://git-scm.com/docs/git-merge#_merge_strategies) doc for all possible values | "theirs" |
|
||||||
|
| Cherry-pick Options | --cherry-pick-options | N | Additional cherry-pick options, see [git-cherry-pick](https://git-scm.com/docs/git-cherry-pick) doc for all possible values | "theirs" |
|
||||||
| Additional comments | --comments | N | Semicolon separated list of additional comments to be posted to the backported pull request | [] |
|
| Additional comments | --comments | N | Semicolon separated list of additional comments to be posted to the backported pull request | [] |
|
||||||
|
| Enable error notification | --enable-err-notification | N | If true, enable the error notification as comment on the original pull request | 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` or `target branch pattern`) are *mandatory*, they must be provided as CLI options or as part of the configuration file (if used).
|
||||||
|
|
||||||
#### Authorization token
|
#### Authorization token
|
||||||
|
|
||||||
|
@ -244,23 +263,6 @@ For a complete description of all inputs see [Inputs section](#inputs).
|
||||||
- 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.
|
||||||
|
|
||||||
## Migrating to v4
|
|
||||||
|
|
||||||
From version `v4` 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:
|
|
||||||
|
|
||||||
> **NOTE**: these changes did not affect the tool features.
|
|
||||||
|
|
||||||
| | **v4 (after migration)** | v3 or older (before migration) |
|
|
||||||
|-------------|--------------------------|--------------------------------|
|
|
||||||
| Owner | kiegroup | lampajr |
|
|
||||||
| Repository | git-backporting | backporting |
|
|
||||||
| NPM package | @kie/git-backporting | @lampajr/bper |
|
|
||||||
| CLI tool | git-backporting | bper |
|
|
||||||
|
|
||||||
So everytime you would use older version keep in mind that these changes are madnatory to make the tool working.
|
|
||||||
|
|
||||||
> **NOTE**: Versions `v3.1.1` and `v4.0.0` offer identical features; the only distinction lies in the project's renaming and organization movement.
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Package release
|
### Package release
|
||||||
|
|
89
action.yml
89
action.yml
|
@ -1,78 +1,119 @@
|
||||||
name: "Backporting GitHub Action"
|
name: "Backporting GitHub Action"
|
||||||
description: "GitHub action providing an automated way to backport pull requests from one branch to another"
|
description: GitHub action providing an automated way to backport pull requests from one branch to another
|
||||||
inputs:
|
inputs:
|
||||||
pull-request:
|
pull-request:
|
||||||
description: "URL of the pull request to backport, e.g., https://github.com/kiegroup/git-backporting/pull/1"
|
description: >
|
||||||
|
URL of the pull request to backport, e.g., "https://github.com/kiegroup/git-backporting/pull/1"
|
||||||
required: false
|
required: false
|
||||||
target-branch:
|
target-branch:
|
||||||
description: "Comma separated list of branches where the pull request must be backported to"
|
description: >
|
||||||
|
Comma separated list of branches where the pull request must be backported to
|
||||||
|
required: false
|
||||||
|
target-branch-pattern:
|
||||||
|
description: >
|
||||||
|
Regular expression pattern to extract target branch(es) from pr labels.
|
||||||
|
The branches will be extracted from the pattern's required `target` named capturing group,
|
||||||
|
for instance "^backport (?<target>([^ ]+))$"
|
||||||
required: false
|
required: false
|
||||||
config-file:
|
config-file:
|
||||||
description: "Path to a file containing the json configuration for this tool, the object must match the Args interface"
|
description: >
|
||||||
|
Path to a file containing the json configuration for this tool,
|
||||||
|
the object must match the Args interface
|
||||||
required: false
|
required: false
|
||||||
dry-run:
|
dry-run:
|
||||||
description: "If enabled the tool does not create any pull request nor push anything remotely"
|
description: >
|
||||||
|
If enabled the tool does not create any pull request nor push anything remotely
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: "false"
|
||||||
auth:
|
auth:
|
||||||
description: "GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT), if not provided will look for existing env variables like GITHUB_TOKEN"
|
description: >
|
||||||
|
GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT),
|
||||||
|
if not provided will look for existing env variables like GITHUB_TOKEN
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
required: false
|
required: false
|
||||||
git-client:
|
git-client:
|
||||||
description: "Git client type <github|gitlab|codeberg>, if not set it is infered from pull-request"
|
description: >
|
||||||
|
Git client type <github|gitlab|codeberg>, if not set it is infered from pull-request
|
||||||
required: false
|
required: false
|
||||||
git-user:
|
git-user:
|
||||||
description: "Local git user name"
|
description: Local git user name
|
||||||
default: "GitHub"
|
default: "GitHub"
|
||||||
required: false
|
required: false
|
||||||
git-email:
|
git-email:
|
||||||
description: "Local git user email"
|
description: Local git user email
|
||||||
default: "noreply@github.com"
|
default: "noreply@github.com"
|
||||||
required: false
|
required: false
|
||||||
title:
|
title:
|
||||||
description: "Backporting PR title. Default is the original PR title prefixed by the target branch"
|
description: >
|
||||||
|
Backporting PR title. Default is the original PR title prefixed by the target branch
|
||||||
required: false
|
required: false
|
||||||
body-prefix:
|
body-prefix:
|
||||||
description: "Backporting PR body prefix. Default is `Backport: <original-pr-link>`"
|
description: >
|
||||||
|
Backporting PR body prefix. Default is `Backport: <original-pr-link>`
|
||||||
required: false
|
required: false
|
||||||
body:
|
body:
|
||||||
description: "Backporting PR body. Default is the original PR body"
|
description: >
|
||||||
|
Backporting PR body. Default is the original PR body
|
||||||
required: false
|
required: false
|
||||||
bp-branch-name:
|
bp-branch-name:
|
||||||
description: "Comma separated list of backporting PR branch names. Default is auto-generated from commit and target branches"
|
description: >
|
||||||
|
Comma separated list of backporting PR branch names.
|
||||||
|
Default is auto-generated from commit and target branches
|
||||||
required: false
|
required: false
|
||||||
reviewers:
|
reviewers:
|
||||||
description: "Comma separated list of reviewers for the backporting pull request"
|
description: >
|
||||||
|
Comma separated list of reviewers for the backporting pull request
|
||||||
required: false
|
required: false
|
||||||
assignees:
|
assignees:
|
||||||
description: "Comma separated list of reviewers for the backporting pull request"
|
description: >
|
||||||
|
Comma separated list of reviewers for the backporting pull request
|
||||||
required: false
|
required: false
|
||||||
no-inherit-reviewers:
|
no-inherit-reviewers:
|
||||||
description: "Considered only if reviewers is empty, if true keep reviewers as empty list, otherwise inherit from original pull request"
|
description: >
|
||||||
|
Considered only if reviewers is empty, if true keep reviewers as empty list,
|
||||||
|
otherwise inherit from original pull request
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: "false"
|
||||||
labels:
|
labels:
|
||||||
description: "Comma separated list of labels to be assigned to the backported pull request"
|
description: >
|
||||||
|
Comma separated list of labels to be assigned to the backported pull request
|
||||||
required: false
|
required: false
|
||||||
inherit-labels:
|
inherit-labels:
|
||||||
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:
|
no-squash:
|
||||||
description: "If set to true the tool will backport all commits as part of the pull request instead of the suqashed one"
|
description: >
|
||||||
|
Backport all commits found in the pull request.
|
||||||
|
The default behavior is to only backport the first commit that was merged in the base branch.
|
||||||
|
required: false
|
||||||
|
auto-no-squash:
|
||||||
|
description: >
|
||||||
|
If the pull request was merged or is open, backport all commits.
|
||||||
|
If the pull request commits were squashed, backport the squashed commit.
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
|
||||||
strategy:
|
strategy:
|
||||||
description: "Cherry-pick merge strategy"
|
description: Cherry-pick merge strategy
|
||||||
required: false
|
required: false
|
||||||
default: "recursive"
|
default: "recursive"
|
||||||
strategy-option:
|
strategy-option:
|
||||||
description: "Cherry-pick merge strategy option"
|
description: Cherry-pick merge strategy option
|
||||||
required: false
|
required: false
|
||||||
default: "theirs"
|
default: "theirs"
|
||||||
comments:
|
cherry-pick-options:
|
||||||
description: "Semicolon separated list of additional comments to be posted to the backported pull request"
|
description: >
|
||||||
|
Additional cherry-pick options
|
||||||
required: false
|
required: false
|
||||||
|
comments:
|
||||||
|
description: >
|
||||||
|
Semicolon separated list of additional comments to be posted to the backported pull request
|
||||||
|
required: false
|
||||||
|
enable-err-notification:
|
||||||
|
description: >
|
||||||
|
If true, enable the error notification as comment on the original pull request
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node20
|
using: node20
|
||||||
|
|
1962
dist/cli/index.js
vendored
1962
dist/cli/index.js
vendored
File diff suppressed because it is too large
Load diff
1956
dist/gha/index.js
vendored
1956
dist/gha/index.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,7 @@ jobs:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Backporting
|
- name: Backporting
|
||||||
|
|
2
mise.toml
Normal file
2
mise.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[tools]
|
||||||
|
node = "20"
|
9049
package-lock.json
generated
9049
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@kie/git-backporting",
|
"name": "@kie/git-backporting",
|
||||||
"version": "4.6.0",
|
"version": "4.8.5",
|
||||||
"description": "Git backporting is a tool to execute automatic pull request git backporting.",
|
"description": "Git backporting is a tool to execute automatic pull request git backporting.",
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
"@gitbeaker/rest": "^39.1.0",
|
"@gitbeaker/rest": "^39.1.0",
|
||||||
"@kie/mock-github": "^1.1.0",
|
"@kie/mock-github": "^1.1.0",
|
||||||
"@octokit/webhooks-types": "^6.8.0",
|
"@octokit/webhooks-types": "^6.8.0",
|
||||||
"@release-it/conventional-changelog": "^7.0.0",
|
"@release-it/conventional-changelog": "^10.0.0",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/jest": "^29.2.4",
|
"@types/jest": "^29.2.4",
|
||||||
"@types/node": "^18.11.17",
|
"@types/node": "^18.11.17",
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
"husky": "^8.0.2",
|
"husky": "^8.0.2",
|
||||||
"jest": "^29.0.0",
|
"jest": "^29.0.0",
|
||||||
"jest-sonar-reporter": "^2.0.0",
|
"jest-sonar-reporter": "^2.0.0",
|
||||||
"release-it": "^16.1.3",
|
"release-it": "^18.1.2",
|
||||||
"semver": "^7.3.8",
|
"semver": "^7.3.8",
|
||||||
"ts-jest": "^29.0.0",
|
"ts-jest": "^29.0.0",
|
||||||
"ts-node": "^10.8.1",
|
"ts-node": "^10.8.1",
|
||||||
|
|
|
@ -16,14 +16,18 @@ export default abstract class ArgsParser {
|
||||||
public parse(): Args {
|
public parse(): Args {
|
||||||
const args = this.readArgs();
|
const args = this.readArgs();
|
||||||
|
|
||||||
|
if (!args.pullRequest) {
|
||||||
|
throw new Error("Missing option: pull request must be provided");
|
||||||
|
}
|
||||||
// validate and fill with defaults
|
// validate and fill with defaults
|
||||||
if (!args.pullRequest || !args.targetBranch || args.targetBranch.trim().length == 0) {
|
if ((!args.targetBranch || args.targetBranch.trim().length == 0) && !args.targetBranchPattern) {
|
||||||
throw new Error("Missing option: pull request and target branches must be provided");
|
throw new Error("Missing option: target branch(es) or target regular expression must be provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pullRequest: args.pullRequest,
|
pullRequest: args.pullRequest,
|
||||||
targetBranch: args.targetBranch,
|
targetBranch: args.targetBranch,
|
||||||
|
targetBranchPattern: args.targetBranchPattern,
|
||||||
dryRun: this.getOrDefault(args.dryRun, false),
|
dryRun: this.getOrDefault(args.dryRun, false),
|
||||||
auth: this.getOrDefault(args.auth),
|
auth: this.getOrDefault(args.auth),
|
||||||
folder: this.getOrDefault(args.folder),
|
folder: this.getOrDefault(args.folder),
|
||||||
|
@ -40,9 +44,12 @@ export default abstract class ArgsParser {
|
||||||
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),
|
squash: this.getOrDefault(args.squash, true),
|
||||||
|
autoNoSquash: this.getOrDefault(args.autoNoSquash, false),
|
||||||
strategy: this.getOrDefault(args.strategy),
|
strategy: this.getOrDefault(args.strategy),
|
||||||
strategyOption: this.getOrDefault(args.strategyOption),
|
strategyOption: this.getOrDefault(args.strategyOption),
|
||||||
comments: this.getOrDefault(args.comments)
|
cherryPickOptions: this.getOrDefault(args.cherryPickOptions),
|
||||||
|
comments: this.getOrDefault(args.comments),
|
||||||
|
enableErrorNotification: this.getOrDefault(args.enableErrorNotification, false),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -50,7 +50,7 @@ export function getAsSemicolonSeparatedList(value: string): string[] | undefined
|
||||||
return trimmed !== "" ? trimmed.split(";").map(v => v.trim()) : undefined;
|
return trimmed !== "" ? trimmed.split(";").map(v => v.trim()) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAsBooleanOrDefault(value: string): boolean | undefined {
|
export function getAsBooleanOrUndefined(value: string): boolean | undefined {
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
return trimmed !== "" ? trimmed.toLowerCase() === "true" : undefined;
|
||||||
}
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
*/
|
*/
|
||||||
export interface Args {
|
export interface Args {
|
||||||
// NOTE: keep targetBranch as singular and of type string for backward compatibilities
|
// NOTE: keep targetBranch as singular and of type string for backward compatibilities
|
||||||
targetBranch: string, // comma separated list of branches on the target repo where the change should be backported to
|
targetBranch?: string, // comma separated list of branches on the target repo where the change should be backported to
|
||||||
|
targetBranchPattern?: string, // regular expression to extract target branch(es) from pull request labels
|
||||||
pullRequest: string, // url of the pull request to backport
|
pullRequest: string, // url of the pull request to backport
|
||||||
dryRun?: boolean, // if enabled do not push anything remotely
|
dryRun?: boolean, // if enabled do not push anything remotely
|
||||||
auth?: string, // git service auth, like github token
|
auth?: string, // git service auth, like github token
|
||||||
|
@ -21,8 +22,11 @@ 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
|
squash?: boolean,
|
||||||
|
autoNoSquash?: boolean,
|
||||||
strategy?: string, // cherry-pick merge strategy
|
strategy?: string, // cherry-pick merge strategy
|
||||||
strategyOption?: string, // cherry-pick merge strategy option
|
strategyOption?: string, // cherry-pick merge strategy option
|
||||||
|
cherryPickOptions?: string, // additional cherry-pick options
|
||||||
comments?: string[], // additional comments to be posted
|
comments?: string[], // additional comments to be posted
|
||||||
|
enableErrorNotification?: boolean, // enable the error notification on original pull request
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ export default class CLIArgsParser extends ArgsParser {
|
||||||
.version(version)
|
.version(version)
|
||||||
.description(description)
|
.description(description)
|
||||||
.option("-tb, --target-branch <branches>", "comma separated list of branches where changes must be backported to")
|
.option("-tb, --target-branch <branches>", "comma separated list of branches where changes must be backported to")
|
||||||
|
.option("-tbp, --target-branch-pattern <pattern>", "regular expression pattern to extract target branch(es) from pr labels, the branches will be extracted from the pattern's required `target` named capturing group")
|
||||||
.option("-pr, --pull-request <pr-url>", "pull request url, e.g., https://github.com/kiegroup/git-backporting/pull/1")
|
.option("-pr, --pull-request <pr-url>", "pull request url, e.g., https://github.com/kiegroup/git-backporting/pull/1")
|
||||||
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely")
|
.option("-d, --dry-run", "if enabled the tool does not create any pull request nor push anything remotely")
|
||||||
.option("-a, --auth <auth>", "git authentication string, if not provided fallback by looking for existing env variables like GITHUB_TOKEN")
|
.option("-a, --auth <auth>", "git authentication string, if not provided fallback by looking for existing env variables like GITHUB_TOKEN")
|
||||||
|
@ -27,10 +28,13 @@ 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("--no-squash", "backport all commits found in the pull request. The default behavior is to only backport the first commit that was merged in the base branch")
|
||||||
|
.option("--auto-no-squash", "if the pull request was merged or is open, backport all commits. If the pull request commits were squashed, backport the squashed commit.")
|
||||||
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
|
.option("--strategy <strategy>", "cherry-pick merge strategy, default to 'recursive'", undefined)
|
||||||
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
|
.option("--strategy-option <strategy-option>", "cherry-pick merge strategy option, default to 'theirs'")
|
||||||
|
.option("--cherry-pick-options <options>", "additional cherry-pick options")
|
||||||
.option("--comments <comments>", "semicolon separated list of additional comments to be posted to the backported pull request", getAsSemicolonSeparatedList)
|
.option("--comments <comments>", "semicolon separated list of additional comments to be posted to the backported pull request", getAsSemicolonSeparatedList)
|
||||||
|
.option("--enable-err-notification", "if true, enable the error notification as comment on the original 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +53,7 @@ export default class CLIArgsParser extends ArgsParser {
|
||||||
auth: opts.auth,
|
auth: opts.auth,
|
||||||
pullRequest: opts.pullRequest,
|
pullRequest: opts.pullRequest,
|
||||||
targetBranch: opts.targetBranch,
|
targetBranch: opts.targetBranch,
|
||||||
|
targetBranchPattern: opts.targetBranchPattern,
|
||||||
folder: opts.folder,
|
folder: opts.folder,
|
||||||
gitClient: opts.gitClient,
|
gitClient: opts.gitClient,
|
||||||
gitUser: opts.gitUser,
|
gitUser: opts.gitUser,
|
||||||
|
@ -63,9 +68,12 @@ export default class CLIArgsParser extends ArgsParser {
|
||||||
labels: opts.labels,
|
labels: opts.labels,
|
||||||
inheritLabels: opts.inheritLabels,
|
inheritLabels: opts.inheritLabels,
|
||||||
squash: opts.squash,
|
squash: opts.squash,
|
||||||
|
autoNoSquash: opts.autoNoSquash,
|
||||||
strategy: opts.strategy,
|
strategy: opts.strategy,
|
||||||
strategyOption: opts.strategyOption,
|
strategyOption: opts.strategyOption,
|
||||||
|
cherryPickOptions: opts.cherryPickOptions,
|
||||||
comments: opts.comments,
|
comments: opts.comments,
|
||||||
|
enableErrorNotification: opts.enableErrNotification,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import ArgsParser from "@bp/service/args/args-parser";
|
import ArgsParser from "@bp/service/args/args-parser";
|
||||||
import { Args } from "@bp/service/args/args.types";
|
import { Args } from "@bp/service/args/args.types";
|
||||||
import { getInput } from "@actions/core";
|
import { getInput } from "@actions/core";
|
||||||
import { getAsBooleanOrDefault, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";
|
import { getAsBooleanOrUndefined, getAsCleanedCommaSeparatedList, getAsCommaSeparatedList, getAsSemicolonSeparatedList, getOrUndefined, readConfigFile } from "@bp/service/args/args-utils";
|
||||||
|
|
||||||
export default class GHAArgsParser extends ArgsParser {
|
export default class GHAArgsParser extends ArgsParser {
|
||||||
|
|
||||||
|
@ -13,10 +13,11 @@ export default class GHAArgsParser extends ArgsParser {
|
||||||
args = readConfigFile(configFile);
|
args = readConfigFile(configFile);
|
||||||
} else {
|
} else {
|
||||||
args = {
|
args = {
|
||||||
dryRun: getAsBooleanOrDefault(getInput("dry-run")),
|
dryRun: getAsBooleanOrUndefined(getInput("dry-run")),
|
||||||
auth: getOrUndefined(getInput("auth")),
|
auth: getOrUndefined(getInput("auth")),
|
||||||
pullRequest: getInput("pull-request"),
|
pullRequest: getInput("pull-request"),
|
||||||
targetBranch: getInput("target-branch"),
|
targetBranch: getOrUndefined(getInput("target-branch")),
|
||||||
|
targetBranchPattern: getOrUndefined(getInput("target-branch-pattern")),
|
||||||
folder: getOrUndefined(getInput("folder")),
|
folder: getOrUndefined(getInput("folder")),
|
||||||
gitClient: getOrUndefined(getInput("git-client")),
|
gitClient: getOrUndefined(getInput("git-client")),
|
||||||
gitUser: getOrUndefined(getInput("git-user")),
|
gitUser: getOrUndefined(getInput("git-user")),
|
||||||
|
@ -27,13 +28,16 @@ export default class GHAArgsParser extends ArgsParser {
|
||||||
bpBranchName: getOrUndefined(getInput("bp-branch-name")),
|
bpBranchName: getOrUndefined(getInput("bp-branch-name")),
|
||||||
reviewers: getAsCleanedCommaSeparatedList(getInput("reviewers")),
|
reviewers: getAsCleanedCommaSeparatedList(getInput("reviewers")),
|
||||||
assignees: getAsCleanedCommaSeparatedList(getInput("assignees")),
|
assignees: getAsCleanedCommaSeparatedList(getInput("assignees")),
|
||||||
inheritReviewers: !getAsBooleanOrDefault(getInput("no-inherit-reviewers")),
|
inheritReviewers: !getAsBooleanOrUndefined(getInput("no-inherit-reviewers")),
|
||||||
labels: getAsCommaSeparatedList(getInput("labels")),
|
labels: getAsCommaSeparatedList(getInput("labels")),
|
||||||
inheritLabels: getAsBooleanOrDefault(getInput("inherit-labels")),
|
inheritLabels: getAsBooleanOrUndefined(getInput("inherit-labels")),
|
||||||
squash: !getAsBooleanOrDefault(getInput("no-squash")),
|
squash: !getAsBooleanOrUndefined(getInput("no-squash")),
|
||||||
|
autoNoSquash: getAsBooleanOrUndefined(getInput("auto-no-squash")),
|
||||||
strategy: getOrUndefined(getInput("strategy")),
|
strategy: getOrUndefined(getInput("strategy")),
|
||||||
strategyOption: getOrUndefined(getInput("strategy-option")),
|
strategyOption: getOrUndefined(getInput("strategy-option")),
|
||||||
|
cherryPickOptions: getOrUndefined(getInput("cherry-pick-options")),
|
||||||
comments: getAsSemicolonSeparatedList(getInput("comments")),
|
comments: getAsSemicolonSeparatedList(getInput("comments")),
|
||||||
|
enableErrorNotification: getAsBooleanOrUndefined(getInput("enable-err-notification")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,19 @@
|
||||||
|
|
||||||
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
||||||
|
|
||||||
|
export const MESSAGE_ERROR_PLACEHOLDER = "{{error}}";
|
||||||
|
export const MESSAGE_TARGET_BRANCH_PLACEHOLDER = "{{target-branch}}";
|
||||||
|
|
||||||
export interface LocalGit {
|
export interface LocalGit {
|
||||||
user: string, // local git user
|
user: string, // local git user
|
||||||
email: string, // local git email
|
email: string, // local git email
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ErrorNotification {
|
||||||
|
enabled: boolean, // if the error notification is enabled
|
||||||
|
message: string, // notification message, placeholder {{error}} will be replaced with actual error
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal configuration object
|
* Internal configuration object
|
||||||
*/
|
*/
|
||||||
|
@ -17,8 +25,10 @@ export interface Configs {
|
||||||
folder: string,
|
folder: string,
|
||||||
mergeStrategy?: string, // cherry-pick merge strategy
|
mergeStrategy?: string, // cherry-pick merge strategy
|
||||||
mergeStrategyOption?: string, // cherry-pick merge strategy option
|
mergeStrategyOption?: string, // cherry-pick merge strategy option
|
||||||
|
cherryPickOptions?: string, // additional cherry-pick options
|
||||||
originalPullRequest: GitPullRequest,
|
originalPullRequest: GitPullRequest,
|
||||||
backportPullRequests: BackportPullRequest[],
|
backportPullRequests: BackportPullRequest[],
|
||||||
|
errorNotification: ErrorNotification,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AuthTokenId {
|
export enum AuthTokenId {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { getAsCleanedCommaSeparatedList, getAsCommaSeparatedList } from "@bp/service/args/args-utils";
|
import { getAsCleanedCommaSeparatedList, getAsCommaSeparatedList } from "@bp/service/args/args-utils";
|
||||||
import { Args } from "@bp/service/args/args.types";
|
import { Args } from "@bp/service/args/args.types";
|
||||||
import ConfigsParser from "@bp/service/configs/configs-parser";
|
import ConfigsParser from "@bp/service/configs/configs-parser";
|
||||||
import { Configs } from "@bp/service/configs/configs.types";
|
import { Configs, MESSAGE_TARGET_BRANCH_PLACEHOLDER } from "@bp/service/configs/configs.types";
|
||||||
import GitClient from "@bp/service/git/git-client";
|
import GitClient from "@bp/service/git/git-client";
|
||||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||||
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
||||||
|
@ -17,8 +17,11 @@ 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;
|
||||||
|
if (args.autoNoSquash) {
|
||||||
|
args.squash = undefined;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
pr = await this.gitClient.getPullRequestFromUrl(args.pullRequest, args.squash!);
|
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;
|
||||||
|
@ -26,7 +29,17 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
|
|
||||||
const folder: string = args.folder ?? this.getDefaultFolder();
|
const folder: string = args.folder ?? this.getDefaultFolder();
|
||||||
|
|
||||||
const targetBranches: string[] = [...new Set(getAsCommaSeparatedList(args.targetBranch)!)];
|
let targetBranches: string[] = [];
|
||||||
|
if (args.targetBranchPattern) {
|
||||||
|
// parse labels to extract target branch(es)
|
||||||
|
targetBranches = this.getTargetBranchesFromLabels(args.targetBranchPattern, pr.labels);
|
||||||
|
if (targetBranches.length === 0) {
|
||||||
|
throw new Error(`Unable to extract target branches with regular expression "${args.targetBranchPattern}"`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// target branch must be provided if targetRegExp is missing
|
||||||
|
targetBranches = [...new Set(getAsCommaSeparatedList(args.targetBranch!)!)];
|
||||||
|
}
|
||||||
const bpBranchNames: string[] = [...new Set(args.bpBranchName ? (getAsCleanedCommaSeparatedList(args.bpBranchName) ?? []) : [])];
|
const bpBranchNames: string[] = [...new Set(args.bpBranchName ? (getAsCleanedCommaSeparatedList(args.bpBranchName) ?? []) : [])];
|
||||||
|
|
||||||
if (bpBranchNames.length > 1 && bpBranchNames.length != targetBranches.length) {
|
if (bpBranchNames.length > 1 && bpBranchNames.length != targetBranches.length) {
|
||||||
|
@ -39,12 +52,17 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
folder: `${folder.startsWith("/") ? "" : process.cwd() + "/"}${args.folder ?? this.getDefaultFolder()}`,
|
||||||
mergeStrategy: args.strategy,
|
mergeStrategy: args.strategy,
|
||||||
mergeStrategyOption: args.strategyOption,
|
mergeStrategyOption: args.strategyOption,
|
||||||
|
cherryPickOptions: args.cherryPickOptions,
|
||||||
originalPullRequest: pr,
|
originalPullRequest: pr,
|
||||||
backportPullRequests: this.generateBackportPullRequestsData(pr, args, targetBranches, bpBranchNames),
|
backportPullRequests: this.generateBackportPullRequestsData(pr, args, targetBranches, bpBranchNames),
|
||||||
git: {
|
git: {
|
||||||
user: args.gitUser ?? this.gitClient.getDefaultGitUser(),
|
user: args.gitUser ?? this.gitClient.getDefaultGitUser(),
|
||||||
email: args.gitEmail ?? this.gitClient.getDefaultGitEmail(),
|
email: args.gitEmail ?? this.gitClient.getDefaultGitEmail(),
|
||||||
}
|
},
|
||||||
|
errorNotification: {
|
||||||
|
enabled: args.enableErrorNotification ?? false,
|
||||||
|
message: this.getDefaultErrorComment(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +70,38 @@ export default class PullRequestConfigsParser extends ConfigsParser {
|
||||||
return "bp";
|
return "bp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getDefaultErrorComment(): string {
|
||||||
|
// TODO: fetch from arg or set default with placeholder {{error}}
|
||||||
|
return `The backport to \`${MESSAGE_TARGET_BRANCH_PLACEHOLDER}\` failed. Check the latest run for more details.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the provided labels and return a list of target branches
|
||||||
|
* obtained by applying the provided pattern as regular expression extractor
|
||||||
|
* @param pattern reg exp pattern to extract target branch from label name
|
||||||
|
* @param labels list of labels to check
|
||||||
|
* @returns list of target branches
|
||||||
|
*/
|
||||||
|
private getTargetBranchesFromLabels(pattern: string, labels: string[]): string[] {
|
||||||
|
this.logger.debug(`Extracting branches from [${labels}] using ${pattern}`);
|
||||||
|
const regExp = new RegExp(pattern);
|
||||||
|
|
||||||
|
const branches: string[] = [];
|
||||||
|
for (const l of labels) {
|
||||||
|
const result = regExp.exec(l);
|
||||||
|
|
||||||
|
if (result?.groups) {
|
||||||
|
const { target } = result.groups;
|
||||||
|
if (target){
|
||||||
|
branches.push(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return [...new Set(branches)];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a backport pull request starting from the target branch and
|
* Create a backport pull request starting from the target branch and
|
||||||
* the original pr to be backported
|
* the original pr to be backported
|
||||||
|
|
|
@ -68,6 +68,15 @@ export default class GitCLIService {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.info(`Folder ${to} already exist. Won't clone`);
|
this.logger.info(`Folder ${to} already exist. Won't clone`);
|
||||||
|
|
||||||
|
// ensure the working tree is properly reset - no stale changes
|
||||||
|
// from previous (failed) backport
|
||||||
|
const ongoingCherryPick = await this.anyConflict(to);
|
||||||
|
if (ongoingCherryPick) {
|
||||||
|
this.logger.warn("Found previously failed cherry-pick, aborting it");
|
||||||
|
await this.git(to).raw(["cherry-pick", "--abort"]);
|
||||||
|
}
|
||||||
|
|
||||||
// checkout to the proper branch
|
// checkout to the proper branch
|
||||||
this.logger.info(`Checking out branch ${branch}`);
|
this.logger.info(`Checking out branch ${branch}`);
|
||||||
await this.git(to).checkout(branch);
|
await this.git(to).checkout(branch);
|
||||||
|
@ -110,10 +119,15 @@ export default class GitCLIService {
|
||||||
* @param cwd repository in which the sha should be cherry picked to
|
* @param cwd repository in which the sha should be cherry picked to
|
||||||
* @param sha commit sha
|
* @param sha commit sha
|
||||||
*/
|
*/
|
||||||
async cherryPick(cwd: string, sha: string, strategy = "recursive", strategyOption = "theirs"): Promise<void> {
|
async cherryPick(cwd: string, sha: string, strategy = "recursive", strategyOption = "theirs", cherryPickOptions: string | undefined): Promise<void> {
|
||||||
this.logger.info(`Cherry picking ${sha}`);
|
this.logger.info(`Cherry picking ${sha}`);
|
||||||
|
|
||||||
const options = ["cherry-pick", "-m", "1", `--strategy=${strategy}`, `--strategy-option=${strategyOption}`, sha];
|
let options = ["cherry-pick", "-m", "1", `--strategy=${strategy}`, `--strategy-option=${strategyOption}`];
|
||||||
|
if (cherryPickOptions !== undefined) {
|
||||||
|
options = options.concat(cherryPickOptions.split(" "));
|
||||||
|
}
|
||||||
|
options.push(sha);
|
||||||
|
this.logger.debug(`Cherry picking command git ${options}`);
|
||||||
try {
|
try {
|
||||||
await this.git(cwd).raw(options);
|
await this.git(cwd).raw(options);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
@ -126,6 +140,21 @@ export default class GitCLIService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether there are some conflicts in the current working directory
|
||||||
|
* which means there is an ongoing cherry-pick that did not complete successfully
|
||||||
|
* @param cwd repository in which the check should be performed
|
||||||
|
* @return true if there is some conflict, false otherwise
|
||||||
|
*/
|
||||||
|
async anyConflict(cwd: string): Promise<boolean> {
|
||||||
|
const status = await this.git(cwd).status();
|
||||||
|
if (status.conflicted.length > 0) {
|
||||||
|
this.logger.debug(`Found conflicts in branch ${status.current}`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push a branch to a remote
|
* Push a branch to a remote
|
||||||
* @param cwd repository in which the push should be performed
|
* @param cwd repository in which the push should be performed
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
||||||
* @param squash if true keep just one single commit, otherwise get the full list
|
* @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, squash: boolean): Promise<GitPullRequest>;
|
getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean | undefined): Promise<GitPullRequest>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pull request object from the underneath git service
|
* Get a pull request object from the underneath git service
|
||||||
|
@ -33,7 +33,7 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
||||||
* @param squash if true keep just one single commit, otherwise get the full list
|
* @param squash if true keep just one single commit, otherwise get the full list
|
||||||
* @returns {Promise<PullRequest>}
|
* @returns {Promise<PullRequest>}
|
||||||
*/
|
*/
|
||||||
getPullRequestFromUrl(prUrl: string, squash: boolean): Promise<GitPullRequest>;
|
getPullRequestFromUrl(prUrl: string, squash: boolean | undefined): Promise<GitPullRequest>;
|
||||||
|
|
||||||
// WRITE
|
// WRITE
|
||||||
|
|
||||||
|
@ -44,4 +44,11 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
||||||
*/
|
*/
|
||||||
createPullRequest(backport: BackportPullRequest): Promise<string>;
|
createPullRequest(backport: BackportPullRequest): Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new comment on the provided pull request
|
||||||
|
* @param prUrl pull request's URL
|
||||||
|
* @param comment comment body
|
||||||
|
*/
|
||||||
|
createPullRequestComment(prUrl: string, comment: string): Promise<string | undefined>;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||||
import { GitClientType } from "@bp/service/git/git.types";
|
import { GitClientType } from "@bp/service/git/git.types";
|
||||||
import { AuthTokenId } from "@bp/service/configs/configs.types";
|
import { AuthTokenId } from "@bp/service/configs/configs.types";
|
||||||
|
|
||||||
|
@ -41,6 +42,29 @@ export const inferGitApiUrl = (prUrl: string, apiVersion = "v4"): string => {
|
||||||
return `${baseUrl}/api/${apiVersion}`;
|
return `${baseUrl}/api/${apiVersion}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer the value of the squash option
|
||||||
|
* @param open true if the pull/merge request is still open
|
||||||
|
* @param squash_commit undefined or null if the pull/merge request was merged, the sha of the squashed commit if it was squashed
|
||||||
|
* @returns true if a single commit must be cherry-picked, false if all merged commits must be cherry-picked
|
||||||
|
*/
|
||||||
|
export const inferSquash = (open: boolean, squash_commit: string | undefined | null): boolean => {
|
||||||
|
const logger = LoggerServiceFactory.getLogger();
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
logger.debug("cherry-pick all commits because they have not been merged (or squashed) in the base branch yet");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (squash_commit) {
|
||||||
|
logger.debug(`cherry-pick the squashed commit ${squash_commit}`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
logger.debug("cherry-pick the merged commit(s)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
|
* Retrieve the git token from env variable, the default is taken from GIT_TOKEN env.
|
||||||
* All specific git env variable have precedence and override the default one.
|
* All specific git env variable have precedence and override the default one.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export interface GitPullRequest {
|
export interface GitPullRequest {
|
||||||
number?: number,
|
number?: number,
|
||||||
author: string,
|
author: string,
|
||||||
url?: string,
|
url: string,
|
||||||
htmlUrl?: string,
|
htmlUrl?: string,
|
||||||
state?: GitRepoState,
|
state?: GitRepoState,
|
||||||
merged?: boolean,
|
merged?: boolean,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import GitClient from "@bp/service/git/git-client";
|
import GitClient from "@bp/service/git/git-client";
|
||||||
|
import { inferSquash } from "@bp/service/git/git-util";
|
||||||
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
|
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
|
||||||
import GitHubMapper from "@bp/service/git/github/github-mapper";
|
import GitHubMapper from "@bp/service/git/github/github-mapper";
|
||||||
import OctokitFactory from "@bp/service/git/github/octokit-factory";
|
import OctokitFactory from "@bp/service/git/github/octokit-factory";
|
||||||
|
@ -37,7 +38,7 @@ export default class GitHubClient implements GitClient {
|
||||||
return "noreply@github.com";
|
return "noreply@github.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPullRequest(owner: string, repo: string, prNumber: number, squash = true): Promise<GitPullRequest> {
|
async getPullRequest(owner: string, repo: string, prNumber: number, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||||
this.logger.debug(`Fetching pull request ${owner}/${repo}/${prNumber}`);
|
this.logger.debug(`Fetching 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,
|
||||||
|
@ -45,6 +46,22 @@ export default class GitHubClient implements GitClient {
|
||||||
pull_number: prNumber,
|
pull_number: prNumber,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (squash === undefined) {
|
||||||
|
let commit_sha: string | undefined = undefined;
|
||||||
|
const open: boolean = data.state == "open";
|
||||||
|
if (!open) {
|
||||||
|
const commit = await this.octokit.rest.git.getCommit({
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
commit_sha: (data.merge_commit_sha as string),
|
||||||
|
});
|
||||||
|
if (commit.data.parents.length === 1) {
|
||||||
|
commit_sha = (data.merge_commit_sha as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
squash = inferSquash(open, commit_sha);
|
||||||
|
}
|
||||||
|
|
||||||
const commits: string[] = [];
|
const commits: string[] = [];
|
||||||
if (!squash) {
|
if (!squash) {
|
||||||
// fetch all commits
|
// fetch all commits
|
||||||
|
@ -56,6 +73,11 @@ export default class GitHubClient implements GitClient {
|
||||||
});
|
});
|
||||||
|
|
||||||
commits.push(...data.map(c => c.sha));
|
commits.push(...data.map(c => c.sha));
|
||||||
|
if (this.isForCodeberg) {
|
||||||
|
// For some reason, even though Codeberg advertises API compatibility
|
||||||
|
// with GitHub, it returns commits in reversed order.
|
||||||
|
commits.reverse();
|
||||||
|
}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
throw new Error(`Failed to retrieve commits for pull request n. ${prNumber}`);
|
throw new Error(`Failed to retrieve commits for pull request n. ${prNumber}`);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +86,7 @@ export default class GitHubClient implements GitClient {
|
||||||
return this.mapper.mapPullRequest(data as PullRequest, commits);
|
return this.mapper.mapPullRequest(data as PullRequest, commits);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPullRequestFromUrl(prUrl: string, squash = true): Promise<GitPullRequest> {
|
async getPullRequestFromUrl(prUrl: string, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||||
return this.getPullRequest(owner, project, id, squash);
|
return this.getPullRequest(owner, project, id, squash);
|
||||||
}
|
}
|
||||||
|
@ -141,6 +163,29 @@ export default class GitHubClient implements GitClient {
|
||||||
return data.html_url;
|
return data.html_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createPullRequestComment(prUrl: string, comment: string): Promise<string | undefined> {
|
||||||
|
let commentUrl: string | undefined = undefined;
|
||||||
|
try {
|
||||||
|
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||||
|
const { data } = await this.octokit.issues.createComment({
|
||||||
|
owner: owner,
|
||||||
|
repo: project,
|
||||||
|
issue_number: id,
|
||||||
|
body: comment
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw new Error("Pull request comment creation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
commentUrl = data.url;
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`Error creating comment on pull request ${prUrl}: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return commentUrl;
|
||||||
|
}
|
||||||
|
|
||||||
// UTILS
|
// UTILS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,8 +24,8 @@ export default class GitHubMapper implements GitResponseMapper<PullRequest, "ope
|
||||||
state: this.mapGitState(pr.state), // TODO fix using custom mapper
|
state: this.mapGitState(pr.state), // TODO fix using custom mapper
|
||||||
merged: pr.merged ?? false,
|
merged: pr.merged ?? false,
|
||||||
mergedBy: pr.merged_by?.login,
|
mergedBy: pr.merged_by?.login,
|
||||||
reviewers: pr.requested_reviewers?.filter(r => "login" in r).map((r => (r as User)?.login)) ?? [],
|
reviewers: pr.requested_reviewers?.filter(r => r && "login" in r).map((r => (r as User)?.login)) ?? [],
|
||||||
assignees: pr.assignees?.filter(r => "login" in r).map(r => r.login) ?? [],
|
assignees: pr.assignees?.filter(r => r && "login" in r).map(r => r.login) ?? [],
|
||||||
labels: pr.labels?.map(l => l.name) ?? [],
|
labels: pr.labels?.map(l => l.name) ?? [],
|
||||||
sourceRepo: await this.mapSourceRepo(pr),
|
sourceRepo: await this.mapSourceRepo(pr),
|
||||||
targetRepo: await this.mapTargetRepo(pr),
|
targetRepo: await this.mapTargetRepo(pr),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import LoggerService from "@bp/service/logger/logger-service";
|
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 { inferSquash } from "@bp/service/git/git-util";
|
||||||
import { GitPullRequest, BackportPullRequest, GitClientType } from "@bp/service/git/git.types";
|
import { GitPullRequest, BackportPullRequest, GitClientType } 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 { CommitSchema, MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
import { CommitSchema, MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
||||||
|
@ -45,9 +46,15 @@ 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, squash = true): Promise<GitPullRequest> {
|
async getPullRequest(namespace: string, repo: string, mrNumber: number, squash: boolean | undefined): 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 url = `/projects/${projectId}/merge_requests/${mrNumber}`;
|
||||||
|
this.logger.debug(`Fetching pull request ${url}`);
|
||||||
|
const { data } = await this.client.get(`${url}`);
|
||||||
|
|
||||||
|
if (squash === undefined) {
|
||||||
|
squash = inferSquash(data.state === "opened", data.squash_commit_sha);
|
||||||
|
}
|
||||||
|
|
||||||
const commits: string[] = [];
|
const commits: string[] = [];
|
||||||
if (!squash) {
|
if (!squash) {
|
||||||
|
@ -65,7 +72,7 @@ export default class GitLabClient implements GitClient {
|
||||||
return this.mapper.mapPullRequest(data as MergeRequestSchema, commits);
|
return this.mapper.mapPullRequest(data as MergeRequestSchema, commits);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPullRequestFromUrl(mrUrl: string, squash = true): Promise<GitPullRequest> {
|
getPullRequestFromUrl(mrUrl: string, squash: boolean | undefined): Promise<GitPullRequest> {
|
||||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||||
return this.getPullRequest(namespace, project, id, squash);
|
return this.getPullRequest(namespace, project, id, squash);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +164,29 @@ export default class GitLabClient implements GitClient {
|
||||||
return mr.web_url;
|
return mr.web_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://docs.gitlab.com/ee/api/notes.html#create-new-issue-note
|
||||||
|
async createPullRequestComment(mrUrl: string, comment: string): Promise<string | undefined> {
|
||||||
|
const commentUrl: string | undefined = undefined;
|
||||||
|
try{
|
||||||
|
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||||
|
const projectId = this.getProjectId(namespace, project);
|
||||||
|
|
||||||
|
const { data } = await this.client.post(`/projects/${projectId}/merge_requests/${id}/notes`, {
|
||||||
|
body: comment,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw new Error("Merge request comment creation failed");
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
this.logger.error(`Error creating comment on merge request ${mrUrl}: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return commentUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTILS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a gitlab user given its username
|
* Retrieve a gitlab user given its username
|
||||||
* @param username
|
* @param username
|
||||||
|
|
|
@ -16,6 +16,10 @@ export default class ConsoleLoggerService implements LoggerService {
|
||||||
this.context = newContext;
|
this.context = newContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getContext(): string | undefined {
|
||||||
|
return this.context;
|
||||||
|
}
|
||||||
|
|
||||||
clearContext() {
|
clearContext() {
|
||||||
this.context = undefined;
|
this.context = undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ export default interface LoggerService {
|
||||||
|
|
||||||
setContext(newContext: string): void;
|
setContext(newContext: string): void;
|
||||||
|
|
||||||
|
getContext(): string | undefined;
|
||||||
|
|
||||||
clearContext(): void;
|
clearContext(): void;
|
||||||
|
|
||||||
trace(message: string): void;
|
trace(message: string): void;
|
||||||
|
|
22
src/service/runner/runner-util.ts
Normal file
22
src/service/runner/runner-util.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { MESSAGE_ERROR_PLACEHOLDER, MESSAGE_TARGET_BRANCH_PLACEHOLDER } from "@bp/service/configs/configs.types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject the error message in the provided `message`.
|
||||||
|
* This is injected in place of the MESSAGE_ERROR_PLACEHOLDER placeholder
|
||||||
|
* @param message string that needs to be updated
|
||||||
|
* @param errMsg the error message that needs to be injected
|
||||||
|
*/
|
||||||
|
export const injectError = (message: string, errMsg: string): string => {
|
||||||
|
return message.replace(MESSAGE_ERROR_PLACEHOLDER, errMsg);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject the target branch into the provided `message`.
|
||||||
|
* This is injected in place of the MESSAGE_TARGET_BRANCH_PLACEHOLDER placeholder
|
||||||
|
* @param message string that needs to be updated
|
||||||
|
* @param targetBranch the target branch to inject
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const injectTargetBranch = (message: string, targetBranch: string): string => {
|
||||||
|
return message.replace(MESSAGE_TARGET_BRANCH_PLACEHOLDER, targetBranch);
|
||||||
|
};
|
|
@ -9,6 +9,7 @@ import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/
|
||||||
import LoggerService from "@bp/service/logger/logger-service";
|
import LoggerService from "@bp/service/logger/logger-service";
|
||||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||||
import { inferGitClient, inferGitApiUrl, getGitTokenFromEnv } from "@bp/service/git/git-util";
|
import { inferGitClient, inferGitApiUrl, getGitTokenFromEnv } from "@bp/service/git/git-util";
|
||||||
|
import { injectError, injectTargetBranch } from "./runner-util";
|
||||||
|
|
||||||
interface Git {
|
interface Git {
|
||||||
gitClientType: GitClientType;
|
gitClientType: GitClientType;
|
||||||
|
@ -92,6 +93,12 @@ export default class Runner {
|
||||||
});
|
});
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
this.logger.error(`Something went wrong backporting to ${pr.base}: ${error}`);
|
this.logger.error(`Something went wrong backporting to ${pr.base}: ${error}`);
|
||||||
|
if (!configs.dryRun && configs.errorNotification.enabled && configs.errorNotification.message.length > 0) {
|
||||||
|
// notify the failure as comment in the original pull request
|
||||||
|
let comment = injectError(configs.errorNotification.message, error as string);
|
||||||
|
comment = injectTargetBranch(comment, pr.base);
|
||||||
|
await gitApi.createPullRequestComment(configs.originalPullRequest.url, comment);
|
||||||
|
}
|
||||||
failures.push(error as string);
|
failures.push(error as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +140,6 @@ export default class Runner {
|
||||||
|
|
||||||
// 5. create new branch from target one and checkout
|
// 5. create new branch from target one and checkout
|
||||||
this.logger.debug("Creating local branch..");
|
this.logger.debug("Creating local branch..");
|
||||||
|
|
||||||
await git.gitCli.createLocalBranch(configs.folder, backportPR.head);
|
await git.gitCli.createLocalBranch(configs.folder, backportPR.head);
|
||||||
|
|
||||||
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
||||||
|
@ -146,8 +152,8 @@ export default class Runner {
|
||||||
|
|
||||||
// 7. apply all changes to the new branch
|
// 7. apply all changes to the new branch
|
||||||
this.logger.debug("Cherry picking commits..");
|
this.logger.debug("Cherry picking commits..");
|
||||||
for (const sha of originalPR.commits!) {
|
for (const sha of originalPR.commits) {
|
||||||
await git.gitCli.cherryPick(configs.folder, sha, configs.mergeStrategy, configs.mergeStrategyOption);
|
await git.gitCli.cherryPick(configs.folder, sha, configs.mergeStrategy, configs.mergeStrategyOption, configs.cherryPickOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configs.dryRun) {
|
if (!configs.dryRun) {
|
||||||
|
|
|
@ -79,8 +79,11 @@ describe("cli args parser", () => {
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
|
expect(args.autoNoSquash).toEqual(false);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
|
expect(args.enableErrorNotification).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("with config file [default, short]", () => {
|
test("with config file [default, short]", () => {
|
||||||
|
@ -108,8 +111,11 @@ describe("cli args parser", () => {
|
||||||
expect(args.labels).toEqual([]);
|
expect(args.labels).toEqual([]);
|
||||||
expect(args.inheritLabels).toEqual(false);
|
expect(args.inheritLabels).toEqual(false);
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
|
expect(args.autoNoSquash).toEqual(false);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
|
expect(args.enableErrorNotification).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [default, long]", () => {
|
test("valid execution [default, long]", () => {
|
||||||
|
@ -141,6 +147,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("with config file [default, long]", () => {
|
test("with config file [default, long]", () => {
|
||||||
|
@ -170,6 +177,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, short]", () => {
|
test("valid execution [override, short]", () => {
|
||||||
|
@ -208,6 +216,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override, long]", () => {
|
test("valid execution [override, long]", () => {
|
||||||
|
@ -264,6 +273,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override using config file", () => {
|
test("override using config file", () => {
|
||||||
|
@ -293,6 +303,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ignore custom option when config file is set", () => {
|
test("ignore custom option when config file is set", () => {
|
||||||
|
@ -351,6 +362,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override squash to false", () => {
|
test("override squash to false", () => {
|
||||||
|
@ -383,7 +395,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(false);
|
expect(args.squash).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override cherry pick strategies", () => {
|
test("override cherry pick strategies and options", () => {
|
||||||
addProcessArgs([
|
addProcessArgs([
|
||||||
"--target-branch",
|
"--target-branch",
|
||||||
"target",
|
"target",
|
||||||
|
@ -393,6 +405,8 @@ describe("cli args parser", () => {
|
||||||
"ort",
|
"ort",
|
||||||
"--strategy-option",
|
"--strategy-option",
|
||||||
"ours",
|
"ours",
|
||||||
|
"--cherry-pick-options",
|
||||||
|
"--allow-empty -x",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const args: Args = parser.parse();
|
const args: Args = parser.parse();
|
||||||
|
@ -416,6 +430,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual("ort");
|
expect(args.strategy).toEqual("ort");
|
||||||
expect(args.strategyOption).toEqual("ours");
|
expect(args.strategyOption).toEqual("ours");
|
||||||
|
expect(args.cherryPickOptions).toEqual("--allow-empty -x");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("additional pr comments", () => {
|
test("additional pr comments", () => {
|
||||||
|
@ -479,6 +494,7 @@ describe("cli args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("invalid execution with empty target branch", () => {
|
test("invalid execution with empty target branch", () => {
|
||||||
|
@ -489,7 +505,7 @@ describe("cli args parser", () => {
|
||||||
"https://localhost/whatever/pulls/1"
|
"https://localhost/whatever/pulls/1"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: target branch(es) or target regular expression must be provided");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("invalid execution with missing mandatory target branch", () => {
|
test("invalid execution with missing mandatory target branch", () => {
|
||||||
|
@ -498,15 +514,28 @@ describe("cli args parser", () => {
|
||||||
"https://localhost/whatever/pulls/1"
|
"https://localhost/whatever/pulls/1"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: target branch(es) or target regular expression must be provided");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("invalid execution with missin mandatory pull request", () => {
|
test("invalid execution with missing mandatory pull request", () => {
|
||||||
addProcessArgs([
|
addProcessArgs([
|
||||||
"-tb",
|
"-tb",
|
||||||
"target",
|
"target",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: pull request must be provided");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("enable error notification flag", () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target, old",
|
||||||
|
"-pr",
|
||||||
|
"https://localhost/whatever/pulls/1",
|
||||||
|
"--enable-err-notification",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const args: Args = parser.parse();
|
||||||
|
expect(args.enableErrorNotification).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -72,6 +72,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("valid execution [override]", () => {
|
test("valid execution [override]", () => {
|
||||||
|
@ -113,6 +114,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("using config file", () => {
|
test("using config file", () => {
|
||||||
|
@ -140,6 +142,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ignore custom options when using config file", () => {
|
test("ignore custom options when using config file", () => {
|
||||||
|
@ -182,6 +185,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override squash to false", () => {
|
test("override squash to false", () => {
|
||||||
|
@ -235,6 +239,7 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual("ort");
|
expect(args.strategy).toEqual("ort");
|
||||||
expect(args.strategyOption).toEqual("ours");
|
expect(args.strategyOption).toEqual("ours");
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("additional pr comments", () => {
|
test("additional pr comments", () => {
|
||||||
|
@ -287,16 +292,16 @@ describe("gha args parser", () => {
|
||||||
expect(args.squash).toEqual(true);
|
expect(args.squash).toEqual(true);
|
||||||
expect(args.strategy).toEqual(undefined);
|
expect(args.strategy).toEqual(undefined);
|
||||||
expect(args.strategyOption).toEqual(undefined);
|
expect(args.strategyOption).toEqual(undefined);
|
||||||
|
expect(args.cherryPickOptions).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test("invalid execution with empty target branch", () => {
|
test("invalid execution with empty target branch", () => {
|
||||||
spyGetInput({
|
spyGetInput({
|
||||||
"target-branch": " ",
|
"target-branch": " ",
|
||||||
"pull-request": "https://localhost/whatever/pulls/1"
|
"pull-request": "https://localhost/whatever/pulls/1"
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: target branch(es) or target regular expression must be provided");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("invalid execution with missing mandatory target branch", () => {
|
test("invalid execution with missing mandatory target branch", () => {
|
||||||
|
@ -304,7 +309,7 @@ describe("gha args parser", () => {
|
||||||
"pull-request": "https://localhost/whatever/pulls/1"
|
"pull-request": "https://localhost/whatever/pulls/1"
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: target branch(es) or target regular expression must be provided");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("invalid execution with missin mandatory pull request", () => {
|
test("invalid execution with missin mandatory pull request", () => {
|
||||||
|
@ -312,6 +317,17 @@ describe("gha args parser", () => {
|
||||||
"target-branch": "target,old",
|
"target-branch": "target,old",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => parser.parse()).toThrowError("Missing option: pull request and target branches must be provided");
|
expect(() => parser.parse()).toThrowError("Missing option: pull request must be provided");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("enable error notification flag", () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target,old",
|
||||||
|
"pull-request": "https://localhost/whatever/pulls/1",
|
||||||
|
"enable-err-notification": "true"
|
||||||
|
});
|
||||||
|
|
||||||
|
const args: Args = parser.parse();
|
||||||
|
expect(args.enableErrorNotification).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -57,7 +57,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -353,7 +353,78 @@ describe("github pull request config parser", () => {
|
||||||
dryRun: false,
|
dryRun: false,
|
||||||
auth: "",
|
auth: "",
|
||||||
pullRequest: multipleCommitsPRUrl,
|
pullRequest: multipleCommitsPRUrl,
|
||||||
targetBranch: "v1, v2, v3",
|
targetBranch: "v4, v5, v6",
|
||||||
|
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.folder).toEqual(process.cwd() + "/bp");
|
||||||
|
expect(configs.backportPullRequests.length).toEqual(3);
|
||||||
|
expect(configs.backportPullRequests).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-v4-0404fb9-11da4e3",
|
||||||
|
base: "v4",
|
||||||
|
title: "[v4] 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: [],
|
||||||
|
comments: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-v5-0404fb9-11da4e3",
|
||||||
|
base: "v5",
|
||||||
|
title: "[v5] 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: [],
|
||||||
|
comments: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-v6-0404fb9-11da4e3",
|
||||||
|
base: "v6",
|
||||||
|
title: "[v6] 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: [],
|
||||||
|
comments: [],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("multiple extracted branches and multiple commits", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: multipleCommitsPRUrl,
|
||||||
|
targetBranchPattern: "^backport (?<target>([^ ]+))$",
|
||||||
gitUser: "GitHub",
|
gitUser: "GitHub",
|
||||||
gitEmail: "noreply@github.com",
|
gitEmail: "noreply@github.com",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
|
|
|
@ -89,7 +89,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -139,6 +139,10 @@ describe("github pull request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
|
expect(configs.errorNotification).toEqual({
|
||||||
|
enabled: false,
|
||||||
|
message: "The backport to `{{target-branch}}` failed. Check the latest run for more details."
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("override folder", async () => {
|
test("override folder", async () => {
|
||||||
|
@ -182,9 +186,9 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 4444, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 4444, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"]);
|
||||||
|
|
||||||
expect(configs.dryRun).toEqual(true);
|
expect(configs.dryRun).toEqual(true);
|
||||||
expect(configs.auth).toEqual("whatever");
|
expect(configs.auth).toEqual("whatever");
|
||||||
|
@ -217,8 +221,7 @@ describe("github pull request config parser", () => {
|
||||||
},
|
},
|
||||||
bpBranchName: undefined,
|
bpBranchName: undefined,
|
||||||
nCommits: 2,
|
nCommits: 2,
|
||||||
// taken from head.sha
|
commits: ["0404fb922ab75c3a8aecad5c97d9af388df04695", "11da4e38aa3e577ffde6d546f1c52e53b04d3151"],
|
||||||
commits: ["91748965051fae1330ad58d15cf694e103267c87"]
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -258,7 +261,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -331,7 +334,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -372,7 +375,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -395,7 +398,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -444,7 +447,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -467,7 +470,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -511,14 +514,14 @@ describe("github pull request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
inheritReviewers: false,
|
inheritReviewers: false,
|
||||||
labels: ["custom-label", "original-label"], // also include the one inherited
|
labels: ["custom-label", "backport prod"], // also include the one inherited
|
||||||
inheritLabels: true,
|
inheritLabels: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -541,7 +544,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -566,7 +569,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "New Body Prefix -New Body",
|
body: "New Body Prefix -New Body",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["custom-label", "original-label"],
|
labels: ["custom-label", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -604,7 +607,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -666,7 +669,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -691,7 +694,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "New Body Prefix -New Body",
|
body: "New Body Prefix -New Body",
|
||||||
reviewers: ["user1", "user2"],
|
reviewers: ["user1", "user2"],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["cherry-pick :cherries:", "original-label"],
|
labels: ["cherry-pick :cherries:", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -736,7 +739,11 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: [],
|
labels: [
|
||||||
|
"backport v1",
|
||||||
|
"backport v2",
|
||||||
|
"backport v3",
|
||||||
|
],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -787,7 +794,7 @@ 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).toBeCalledTimes(1);
|
||||||
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, true);
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
@ -810,7 +817,7 @@ describe("github pull request config parser", () => {
|
||||||
body: "Please review and merge",
|
body: "Please review and merge",
|
||||||
reviewers: ["requested-gh-user", "gh-user"],
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["original-label"],
|
labels: ["backport prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
@ -839,4 +846,123 @@ describe("github pull request config parser", () => {
|
||||||
comments: ["First comment", "Second comment"],
|
comments: ["First comment", "Second comment"],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("no extracted target branches from pr labels due to wrong group name", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranchPattern: "^backport (?<wrong>([^ ]+))$",
|
||||||
|
gitUser: "Me",
|
||||||
|
gitEmail: "me@email.com",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body",
|
||||||
|
bodyPrefix: "New Body Prefix -",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
inheritReviewers: false,
|
||||||
|
labels: [],
|
||||||
|
inheritLabels: false,
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(() => configParser.parseAndValidate(args)).rejects.toThrow("Unable to extract target branches with regular expression");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("extract target branches from pr labels", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranchPattern: "^backport (?<target>([^ ]+))$",
|
||||||
|
gitUser: "Me",
|
||||||
|
gitEmail: "me@email.com",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body",
|
||||||
|
bodyPrefix: "New Body Prefix -",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
inheritReviewers: false,
|
||||||
|
labels: [],
|
||||||
|
inheritLabels: false,
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "Me",
|
||||||
|
email: "me@email.com"
|
||||||
|
});
|
||||||
|
expect(configs.auth).toEqual("");
|
||||||
|
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||||
|
expect(configs.originalPullRequest).toEqual({
|
||||||
|
number: 2368,
|
||||||
|
author: "gh-user",
|
||||||
|
url: "https://api.github.com/repos/owner/reponame/pulls/2368",
|
||||||
|
htmlUrl: "https://github.com/owner/reponame/pull/2368",
|
||||||
|
state: "closed",
|
||||||
|
merged: true,
|
||||||
|
mergedBy: "that-s-a-user",
|
||||||
|
title: "PR Title",
|
||||||
|
body: "Please review and merge",
|
||||||
|
reviewers: ["requested-gh-user", "gh-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: ["backport prod"],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "owner",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/owner/reponame.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "fork",
|
||||||
|
project: "reponame",
|
||||||
|
cloneUrl: "https://github.com/fork/reponame.git"
|
||||||
|
},
|
||||||
|
bpBranchName: undefined,
|
||||||
|
nCommits: 2,
|
||||||
|
commits: ["28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc"],
|
||||||
|
});
|
||||||
|
expect(configs.backportPullRequests.length).toEqual(1);
|
||||||
|
expect(configs.backportPullRequests[0]).toEqual({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-prod-28f63db",
|
||||||
|
base: "prod",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix -New Body",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
labels: [],
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("enable error notification message", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
enableErrorNotification: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.getPullRequest).toBeCalledWith("owner", "reponame", 2368, undefined);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.errorNotification).toEqual({
|
||||||
|
"enabled": true,
|
||||||
|
"message": "The backport to `{{target-branch}}` failed. Check the latest run for more details."
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -51,6 +51,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
inheritLabels: false,
|
inheritLabels: false,
|
||||||
comments: [],
|
comments: [],
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -123,6 +124,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
inheritLabels: false,
|
inheritLabels: false,
|
||||||
comments: [],
|
comments: [],
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -195,7 +197,8 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
inheritLabels: false,
|
inheritLabels: false,
|
||||||
comments: [],
|
comments: [],
|
||||||
bpBranchName: "custom-branch"
|
bpBranchName: "custom-branch",
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -268,7 +271,8 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
inheritLabels: false,
|
inheritLabels: false,
|
||||||
comments: [],
|
comments: [],
|
||||||
bpBranchName: "custom1, custom2, custom3"
|
bpBranchName: "custom1, custom2, custom3",
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
|
@ -88,6 +88,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -116,7 +117,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -143,6 +144,10 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
|
expect(configs.errorNotification).toEqual({
|
||||||
|
"enabled": false,
|
||||||
|
"message": "The backport to `{{target-branch}}` failed. Check the latest run for more details."
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,6 +163,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -187,6 +193,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -243,6 +250,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
await expect(() => 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");
|
||||||
|
@ -262,6 +270,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
inheritReviewers: true,
|
inheritReviewers: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -290,7 +299,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -333,6 +342,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: ["user1", "user2"],
|
reviewers: ["user1", "user2"],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
inheritReviewers: true, // not taken into account
|
inheritReviewers: true, // not taken into account
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -361,7 +371,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -404,6 +414,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
inheritReviewers: false,
|
inheritReviewers: false,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -432,7 +443,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -475,8 +486,9 @@ describe("gitlab merge request config parser", () => {
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
inheritReviewers: false,
|
inheritReviewers: false,
|
||||||
labels: ["custom-label", "gitlab-original-label"], // also include the one inherited
|
labels: ["custom-label", "backport-prod"], // also include the one inherited
|
||||||
inheritLabels: true,
|
inheritLabels: true,
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -505,7 +517,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -529,7 +541,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "New Body Prefix -New Body",
|
body: "New Body Prefix -New Body",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["custom-label", "gitlab-original-label"],
|
labels: ["custom-label", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -566,7 +578,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -627,7 +639,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -651,7 +663,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "New Body Prefix -New Body",
|
body: "New Body Prefix -New Body",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["cherry-pick :cherries:", "gitlab-original-label"],
|
labels: ["cherry-pick :cherries:", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -742,6 +754,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
labels: [],
|
labels: [],
|
||||||
inheritLabels: false,
|
inheritLabels: false,
|
||||||
comments: ["First comment", "Second comment"],
|
comments: ["First comment", "Second comment"],
|
||||||
|
squash: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const configs: Configs = await configParser.parseAndValidate(args);
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
@ -770,7 +783,7 @@ describe("gitlab merge request config parser", () => {
|
||||||
body: "This is the body",
|
body: "This is the body",
|
||||||
reviewers: ["superuser1", "superuser2"],
|
reviewers: ["superuser1", "superuser2"],
|
||||||
assignees: ["superuser"],
|
assignees: ["superuser"],
|
||||||
labels: ["gitlab-original-label"],
|
labels: ["backport-prod"],
|
||||||
targetRepo: {
|
targetRepo: {
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -798,4 +811,101 @@ describe("gitlab merge request config parser", () => {
|
||||||
comments: ["First comment", "Second comment"],
|
comments: ["First comment", "Second comment"],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("extract target branches from pr labels", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranchPattern: "^backport-(?<target>([^ ]+))$",
|
||||||
|
gitUser: "Me",
|
||||||
|
gitEmail: "me@email.com",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body",
|
||||||
|
bodyPrefix: "New Body Prefix -",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
inheritReviewers: false,
|
||||||
|
labels: [],
|
||||||
|
inheritLabels: false,
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
squash: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledWith("superuser", "backporting-example", 1, true);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.dryRun).toEqual(false);
|
||||||
|
expect(configs.git).toEqual({
|
||||||
|
user: "Me",
|
||||||
|
email: "me@email.com"
|
||||||
|
});
|
||||||
|
expect(configs.auth).toEqual("");
|
||||||
|
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||||
|
expect(configs.originalPullRequest).toEqual({
|
||||||
|
number: 1,
|
||||||
|
author: "superuser",
|
||||||
|
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||||
|
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||||
|
state: "merged",
|
||||||
|
merged: true,
|
||||||
|
mergedBy: "superuser",
|
||||||
|
title: "Update test.txt",
|
||||||
|
body: "This is the body",
|
||||||
|
reviewers: ["superuser1", "superuser2"],
|
||||||
|
assignees: ["superuser"],
|
||||||
|
labels: ["backport-prod"],
|
||||||
|
targetRepo: {
|
||||||
|
owner: "superuser",
|
||||||
|
project: "backporting-example",
|
||||||
|
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||||
|
},
|
||||||
|
sourceRepo: {
|
||||||
|
owner: "superuser",
|
||||||
|
project: "backporting-example",
|
||||||
|
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||||
|
},
|
||||||
|
nCommits: 1,
|
||||||
|
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
|
||||||
|
});
|
||||||
|
expect(configs.backportPullRequests.length).toEqual(1);
|
||||||
|
expect(configs.backportPullRequests[0]).toEqual({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-prod-ebb1eca",
|
||||||
|
base: "prod",
|
||||||
|
title: "New Title",
|
||||||
|
body: "New Body Prefix -New Body",
|
||||||
|
reviewers: [],
|
||||||
|
assignees: ["user3", "user4"],
|
||||||
|
labels: [],
|
||||||
|
comments: ["First comment", "Second comment"],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("enable error notification message", async () => {
|
||||||
|
const args: Args = {
|
||||||
|
dryRun: false,
|
||||||
|
auth: "",
|
||||||
|
pullRequest: mergedPRUrl,
|
||||||
|
targetBranch: "prod",
|
||||||
|
enableErrorNotification: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Configs = await configParser.parseAndValidate(args);
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.getPullRequest).toBeCalledWith("superuser", "backporting-example", 1, undefined);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabMapper.prototype.mapPullRequest).toBeCalledWith(expect.anything(), []);
|
||||||
|
|
||||||
|
expect(configs.errorNotification).toEqual({
|
||||||
|
"enabled": true,
|
||||||
|
"message": "The backport to `{{target-branch}}` failed. Check the latest run for more details.",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { inferGitApiUrl, inferGitClient } from "@bp/service/git/git-util";
|
import { inferGitApiUrl, inferGitClient, inferSquash } from "@bp/service/git/git-util";
|
||||||
import { GitClientType } from "@bp/service/git/git.types";
|
import { GitClientType } from "@bp/service/git/git.types";
|
||||||
|
|
||||||
describe("check git utilities", () => {
|
describe("check git utilities", () => {
|
||||||
|
@ -54,4 +54,11 @@ describe("check git utilities", () => {
|
||||||
test("check infer codeberg client", ()=> {
|
test("check infer codeberg client", ()=> {
|
||||||
expect(inferGitClient("https://codeberg.org/lampajr/backporting-example/pulls/1")).toStrictEqual(GitClientType.CODEBERG);
|
expect(inferGitClient("https://codeberg.org/lampajr/backporting-example/pulls/1")).toStrictEqual(GitClientType.CODEBERG);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("check inferSquash", ()=> {
|
||||||
|
expect(inferSquash(true, undefined)).toStrictEqual(false);
|
||||||
|
expect(inferSquash(false, "SHA")).toStrictEqual(true);
|
||||||
|
expect(inferSquash(false, undefined)).toStrictEqual(false);
|
||||||
|
expect(inferSquash(false, null)).toStrictEqual(false);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -22,7 +22,7 @@ describe("github service", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("get pull request: success", async () => {
|
test("get pull request: success", async () => {
|
||||||
const res: GitPullRequest = await gitClient.getPullRequest(TARGET_OWNER, REPO, MERGED_PR_FIXTURE.number);
|
const res: GitPullRequest = await gitClient.getPullRequest(TARGET_OWNER, REPO, MERGED_PR_FIXTURE.number, true);
|
||||||
expect(res.sourceRepo).toEqual({
|
expect(res.sourceRepo).toEqual({
|
||||||
owner: "fork",
|
owner: "fork",
|
||||||
project: "reponame",
|
project: "reponame",
|
||||||
|
|
|
@ -31,7 +31,7 @@ describe("github service", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
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, true);
|
||||||
|
|
||||||
// check content
|
// check content
|
||||||
expect(res.sourceRepo).toEqual({
|
expect(res.sourceRepo).toEqual({
|
||||||
|
@ -56,7 +56,7 @@ describe("github service", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("get open pull request", async () => {
|
test("get open pull request", async () => {
|
||||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 2);
|
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 2, true);
|
||||||
expect(res.sourceRepo).toEqual({
|
expect(res.sourceRepo).toEqual({
|
||||||
owner: "superuser",
|
owner: "superuser",
|
||||||
project: "backporting-example",
|
project: "backporting-example",
|
||||||
|
@ -325,7 +325,7 @@ describe("github service", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("get pull request for nested namespaces", async () => {
|
test("get pull request for nested namespaces", async () => {
|
||||||
const res: GitPullRequest = await gitClient.getPullRequestFromUrl("https://my.gitlab.host.com/mysuperorg/6/mysuperproduct/mysuperunit/backporting-example/-/merge_requests/4");
|
const res: GitPullRequest = await gitClient.getPullRequestFromUrl("https://my.gitlab.host.com/mysuperorg/6/mysuperproduct/mysuperunit/backporting-example/-/merge_requests/4", true);
|
||||||
|
|
||||||
// check content
|
// check content
|
||||||
expect(res.sourceRepo).toEqual({
|
expect(res.sourceRepo).toEqual({
|
||||||
|
|
1376
test/service/runner/cli-codeberg-runner.test.ts
Normal file
1376
test/service/runner/cli-codeberg-runner.test.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,7 @@ const GITHUB_MERGED_PR_W_OVERRIDES_CONFIG_FILE_CONTENT = {
|
||||||
|
|
||||||
jest.mock("@bp/service/git/git-cli");
|
jest.mock("@bp/service/git/git-cli");
|
||||||
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
||||||
|
jest.spyOn(GitHubClient.prototype, "createPullRequestComment");
|
||||||
jest.spyOn(GitClientFactory, "getOrCreate");
|
jest.spyOn(GitClientFactory, "getOrCreate");
|
||||||
|
|
||||||
let parser: ArgsParser;
|
let parser: ArgsParser;
|
||||||
|
@ -90,10 +91,11 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("overriding author", async () => {
|
test("overriding author", async () => {
|
||||||
|
@ -119,7 +121,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
@ -153,7 +155,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||||
|
@ -190,7 +192,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
@ -221,7 +223,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -267,7 +269,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -287,6 +289,7 @@ describe("cli runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("closed and not merged pull request", async () => {
|
test("closed and not merged pull request", async () => {
|
||||||
|
@ -300,7 +303,7 @@ describe("cli runner", () => {
|
||||||
await expect(() => 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 simple", async () => {
|
||||||
addProcessArgs([
|
addProcessArgs([
|
||||||
"-tb",
|
"-tb",
|
||||||
"target",
|
"target",
|
||||||
|
@ -325,7 +328,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9174896");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9174896");
|
||||||
|
@ -347,6 +350,55 @@ describe("cli runner", () => {
|
||||||
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("open pull request with --auto-no-squash", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/4444",
|
||||||
|
"--auto-no-squash",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined, undefined);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenLastCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-0404fb9-11da4e3",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/4444\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
test("override backporting pr data", async () => {
|
test("override backporting pr data", async () => {
|
||||||
addProcessArgs([
|
addProcessArgs([
|
||||||
"-tb",
|
"-tb",
|
||||||
|
@ -384,7 +436,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -442,7 +494,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -471,7 +523,7 @@ describe("cli runner", () => {
|
||||||
"-pr",
|
"-pr",
|
||||||
"https://github.com/owner/reponame/pull/2368",
|
"https://github.com/owner/reponame/pull/2368",
|
||||||
"--labels",
|
"--labels",
|
||||||
"cherry-pick :cherries:, original-label",
|
"cherry-pick :cherries:, backport prod",
|
||||||
"--inherit-labels",
|
"--inherit-labels",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -492,7 +544,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -507,7 +559,7 @@ describe("cli runner", () => {
|
||||||
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
reviewers: ["gh-user", "that-s-a-user"],
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["cherry-pick :cherries:", "original-label"],
|
labels: ["cherry-pick :cherries:", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -541,7 +593,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -586,7 +638,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -601,7 +653,7 @@ describe("cli runner", () => {
|
||||||
body: "New Body Prefix - New Body",
|
body: "New Body Prefix - New Body",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["cli github cherry pick :cherries:", "original-label"],
|
labels: ["cli github cherry pick :cherries:", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -634,7 +686,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -681,8 +733,8 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenLastCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||||
|
@ -736,7 +788,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, truncatedBranch);
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, truncatedBranch);
|
||||||
|
@ -787,8 +839,8 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", "ort", "find-renames");
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", "ort", "find-renames", undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", "ort", "find-renames");
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenLastCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", "ort", "find-renames", undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||||
|
@ -838,7 +890,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -891,9 +943,9 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-v1-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-v1-28f63db");
|
||||||
|
@ -973,9 +1025,9 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom1");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom1");
|
||||||
|
@ -1060,9 +1112,9 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-failure-head-v1");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-failure-head-v1");
|
||||||
|
@ -1107,6 +1159,7 @@ describe("cli runner", () => {
|
||||||
comments: [],
|
comments: [],
|
||||||
});
|
});
|
||||||
expect(GitHubClient.prototype.createPullRequest).toThrowError();
|
expect(GitHubClient.prototype.createPullRequest).toThrowError();
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("auth using GITHUB_TOKEN takes precedence over GIT_TOKEN env variable", async () => {
|
test("auth using GITHUB_TOKEN takes precedence over GIT_TOKEN env variable", async () => {
|
||||||
|
@ -1163,4 +1216,161 @@ describe("cli runner", () => {
|
||||||
|
|
||||||
// Not interested in all subsequent calls, already tested in other test cases
|
// Not interested in all subsequent calls, already tested in other test cases
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("extract target branch from label", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"--target-branch-pattern",
|
||||||
|
"^backport (?<target>([^ ]+))$",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/2368"
|
||||||
|
]);
|
||||||
|
|
||||||
|
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, "prod");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("with multiple target branches, one failure and error notification enabled", async () => {
|
||||||
|
jest.spyOn(GitHubClient.prototype, "createPullRequest").mockImplementation((backport: BackportPullRequest) => {
|
||||||
|
throw new Error(`Mocked error: ${backport.base}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"v1, v2, v3",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/2368",
|
||||||
|
"-f",
|
||||||
|
"/tmp/folder",
|
||||||
|
"--bp-branch-name",
|
||||||
|
"custom-failure-head",
|
||||||
|
"--enable-err-notification",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await expect(() => runner.execute()).rejects.toThrowError("Failure occurred during one of the backports: [Error: Mocked error: v1 ; Error: Mocked error: v2 ; Error: Mocked error: v3]");
|
||||||
|
|
||||||
|
const cwd = "/tmp/folder";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v1");
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v2");
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v3");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v1");
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v2");
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v3");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-failure-head-v1");
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-failure-head-v2");
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-failure-head-v3");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(3);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "custom-failure-head-v1",
|
||||||
|
base: "v1",
|
||||||
|
title: "[v1] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
});
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "custom-failure-head-v2",
|
||||||
|
base: "v2",
|
||||||
|
title: "[v2] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
});
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "custom-failure-head-v3",
|
||||||
|
base: "v3",
|
||||||
|
title: "[v3] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
});
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toThrowError();
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(3);
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledWith("https://api.github.com/repos/owner/reponame/pulls/2368", "The backport to `v1` failed. Check the latest run for more details.");
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledWith("https://api.github.com/repos/owner/reponame/pulls/2368", "The backport to `v2` failed. Check the latest run for more details.");
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledWith("https://api.github.com/repos/owner/reponame/pulls/2368", "The backport to `v3` failed. Check the latest run for more details.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("with some failures and dry run enabled", async () => {
|
||||||
|
jest.spyOn(GitCLIService.prototype, "cherryPick").mockImplementation((cwd: string, sha: string) => {
|
||||||
|
throw new Error(`Forced error: ${sha}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"v1, v2, v3",
|
||||||
|
"-pr",
|
||||||
|
"https://github.com/owner/reponame/pull/2368",
|
||||||
|
"-f",
|
||||||
|
"/tmp/folder",
|
||||||
|
"--bp-branch-name",
|
||||||
|
"custom-failure-head",
|
||||||
|
"--enable-err-notification",
|
||||||
|
"--dry-run",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await expect(() => runner.execute()).rejects.toThrowError("Failure occurred during one of the backports: [Error: Forced error: 28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc ; Error: Forced error: 28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc ; Error: Forced error: 28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc]");
|
||||||
|
|
||||||
|
const cwd = "/tmp/folder";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v1");
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v2");
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "v3");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v1");
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v2");
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "custom-failure-head-v3");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toThrowError();
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -44,6 +44,7 @@ jest.mock("axios", () => {
|
||||||
|
|
||||||
jest.mock("@bp/service/git/git-cli");
|
jest.mock("@bp/service/git/git-cli");
|
||||||
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
||||||
|
jest.spyOn(GitLabClient.prototype, "createPullRequestComment");
|
||||||
jest.spyOn(GitClientFactory, "getOrCreate");
|
jest.spyOn(GitClientFactory, "getOrCreate");
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,10 +102,11 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
expect(GitLabClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dry run with relative folder", async () => {
|
test("dry run with relative folder", async () => {
|
||||||
|
@ -135,7 +137,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||||
|
@ -169,7 +171,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674");
|
||||||
|
@ -199,6 +201,7 @@ describe("cli runner", () => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await expect(() => 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");
|
||||||
|
expect(GitLabClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("merged pull request", async () => {
|
test("merged pull request", async () => {
|
||||||
|
@ -227,7 +230,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -246,6 +249,7 @@ describe("cli runner", () => {
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
expect(GitLabClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -286,7 +290,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -343,7 +347,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -393,7 +397,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -408,7 +412,7 @@ describe("cli runner", () => {
|
||||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||||
reviewers: ["superuser"],
|
reviewers: ["superuser"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["cherry-pick :cherries:", "another-label", "gitlab-original-label"],
|
labels: ["cherry-pick :cherries:", "another-label", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -442,7 +446,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -487,7 +491,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-prod-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-prod-ebb1eca");
|
||||||
|
@ -502,7 +506,7 @@ describe("cli runner", () => {
|
||||||
body: expect.stringContaining("**This is a backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
body: expect.stringContaining("**This is a backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["cli gitlab cherry pick :cherries:", "gitlab-original-label"],
|
labels: ["cli gitlab cherry pick :cherries:", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -531,7 +535,7 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336");
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
@ -578,8 +582,8 @@ describe("cli runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenNthCalledWith(1, cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "974519f65c9e0ed65277cd71026657a09fca05e7", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenNthCalledWith(2, cwd, "974519f65c9e0ed65277cd71026657a09fca05e7", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336-974519f");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336-974519f");
|
||||||
|
@ -600,6 +604,50 @@ describe("cli runner", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("merged MR with --auto-no-squash", async () => {
|
||||||
|
addProcessArgs([
|
||||||
|
"-tb",
|
||||||
|
"target",
|
||||||
|
"-pr",
|
||||||
|
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/5",
|
||||||
|
"--auto-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-e4dd336");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-target-e4dd336",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] Update test.txt",
|
||||||
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/5"),
|
||||||
|
reviewers: ["superuser"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("auth using GITLAB_TOKEN takes precedence over GIT_TOKEN env variable", async () => {
|
test("auth using GITLAB_TOKEN takes precedence over GIT_TOKEN env variable", async () => {
|
||||||
process.env[AuthTokenId.GIT_TOKEN] = "mygittoken";
|
process.env[AuthTokenId.GIT_TOKEN] = "mygittoken";
|
||||||
process.env[AuthTokenId.GITLAB_TOKEN] = "mygitlabtoken";
|
process.env[AuthTokenId.GITLAB_TOKEN] = "mygitlabtoken";
|
||||||
|
|
|
@ -30,6 +30,7 @@ const GITHUB_MERGED_PR_W_OVERRIDES_CONFIG_FILE_CONTENT = {
|
||||||
|
|
||||||
jest.mock("@bp/service/git/git-cli");
|
jest.mock("@bp/service/git/git-cli");
|
||||||
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
||||||
|
jest.spyOn(GitHubClient.prototype, "createPullRequestComment");
|
||||||
jest.spyOn(GitClientFactory, "getOrCreate");
|
jest.spyOn(GitClientFactory, "getOrCreate");
|
||||||
|
|
||||||
let parser: ArgsParser;
|
let parser: ArgsParser;
|
||||||
|
@ -83,10 +84,11 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
expect(GitHubClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("without dry run", async () => {
|
test("without dry run", async () => {
|
||||||
|
@ -112,7 +114,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -166,7 +168,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/4444/head:pr/4444");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "91748965051fae1330ad58d15cf694e103267c87", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9174896");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9174896");
|
||||||
|
@ -217,7 +219,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -269,7 +271,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -316,7 +318,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -331,7 +333,7 @@ describe("gha runner", () => {
|
||||||
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
reviewers: ["gh-user", "that-s-a-user"],
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["cherry-pick :cherries:", "another-label", "original-label"],
|
labels: ["cherry-pick :cherries:", "another-label", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -363,7 +365,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -407,7 +409,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -422,7 +424,7 @@ describe("gha runner", () => {
|
||||||
body: "New Body Prefix - New Body",
|
body: "New Body Prefix - New Body",
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["gha github cherry pick :cherries:", "original-label"],
|
labels: ["gha github cherry pick :cherries:", "backport prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -453,7 +455,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -498,8 +500,8 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "0404fb922ab75c3a8aecad5c97d9af388df04695", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toHaveBeenLastCalledWith(cwd, "11da4e38aa3e577ffde6d546f1c52e53b04d3151", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-0404fb9-11da4e3");
|
||||||
|
@ -546,7 +548,53 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", "ort", "ours");
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", "ort", "ours", undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "owner",
|
||||||
|
repo: "reponame",
|
||||||
|
head: "bp-target-28f63db",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] PR Title",
|
||||||
|
body: "**Backport:** https://github.com/owner/reponame/pull/2368\r\n\r\nPlease review and merge",
|
||||||
|
reviewers: ["gh-user", "that-s-a-user"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(GitHubClient.prototype.createPullRequest).toReturnTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("using github api url and additional cherry-pick options", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://api.github.com/repos/owner/reponame/pulls/2368",
|
||||||
|
"cherry-pick-options": "-x --allow-empty",
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.execute();
|
||||||
|
|
||||||
|
const cwd = process.cwd() + "/bp";
|
||||||
|
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledTimes(1);
|
||||||
|
expect(GitClientFactory.getOrCreate).toBeCalledWith(GitClientType.GITHUB, undefined, "https://api.github.com");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.clone).toBeCalledWith("https://github.com/owner/reponame.git", cwd, "target");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, "-x --allow-empty");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -592,7 +640,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db");
|
||||||
|
@ -642,9 +690,9 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-v1-28f63db");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-v1-28f63db");
|
||||||
|
@ -720,9 +768,9 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "pull/2368/head:pr/2368");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(3);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-v1");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "custom-v1");
|
||||||
|
|
|
@ -43,6 +43,7 @@ jest.mock("axios", () => {
|
||||||
|
|
||||||
jest.mock("@bp/service/git/git-cli");
|
jest.mock("@bp/service/git/git-cli");
|
||||||
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
||||||
|
jest.spyOn(GitLabClient.prototype, "createPullRequestComment");
|
||||||
jest.spyOn(GitClientFactory, "getOrCreate");
|
jest.spyOn(GitClientFactory, "getOrCreate");
|
||||||
|
|
||||||
let parser: ArgsParser;
|
let parser: ArgsParser;
|
||||||
|
@ -94,10 +95,11 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||||
|
expect(GitLabClient.prototype.createPullRequestComment).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("without dry run", async () => {
|
test("without dry run", async () => {
|
||||||
|
@ -123,7 +125,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674");
|
||||||
|
@ -175,7 +177,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -225,7 +227,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -276,7 +278,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||||
|
@ -321,7 +323,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -336,7 +338,7 @@ describe("gha runner", () => {
|
||||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||||
reviewers: ["superuser"],
|
reviewers: ["superuser"],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
labels: ["cherry-pick :cherries:", "another-label", "gitlab-original-label"],
|
labels: ["cherry-pick :cherries:", "another-label", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -365,7 +367,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca");
|
||||||
|
@ -409,7 +411,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-prod-ebb1eca");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-prod-ebb1eca");
|
||||||
|
@ -424,7 +426,7 @@ describe("gha runner", () => {
|
||||||
body: expect.stringContaining("**This is a backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
body: expect.stringContaining("**This is a backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||||
reviewers: [],
|
reviewers: [],
|
||||||
assignees: ["user3", "user4"],
|
assignees: ["user3", "user4"],
|
||||||
labels: ["gha gitlab cherry pick :cherries:", "gitlab-original-label"],
|
labels: ["gha gitlab cherry pick :cherries:", "backport-prod"],
|
||||||
comments: [],
|
comments: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -451,7 +453,7 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336");
|
expect(GitCLIService.prototype.createLocalBranch).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
@ -496,8 +498,8 @@ describe("gha runner", () => {
|
||||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||||
|
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(2);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "974519f65c9e0ed65277cd71026657a09fca05e7", undefined, undefined);
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "974519f65c9e0ed65277cd71026657a09fca05e7", undefined, undefined, undefined);
|
||||||
|
|
||||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336-974519f");
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336-974519f");
|
||||||
|
@ -517,4 +519,46 @@ describe("gha runner", () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("merged MR with auto-no-squash", async () => {
|
||||||
|
spyGetInput({
|
||||||
|
"target-branch": "target",
|
||||||
|
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/5",
|
||||||
|
"auto-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-e4dd336");
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "e4dd336a4a20f394df6665994df382fb1d193a11", undefined, undefined, undefined);
|
||||||
|
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||||
|
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-e4dd336");
|
||||||
|
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||||
|
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||||
|
owner: "superuser",
|
||||||
|
repo: "backporting-example",
|
||||||
|
head: "bp-target-e4dd336",
|
||||||
|
base: "target",
|
||||||
|
title: "[target] Update test.txt",
|
||||||
|
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/5"),
|
||||||
|
reviewers: ["superuser"],
|
||||||
|
assignees: [],
|
||||||
|
labels: [],
|
||||||
|
comments: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
19
test/service/runner/runner-util.test.ts
Normal file
19
test/service/runner/runner-util.test.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { injectError, injectTargetBranch } from "@bp/service/runner/runner-util";
|
||||||
|
|
||||||
|
describe("check runner utilities", () => {
|
||||||
|
test("properly inject error message", () => {
|
||||||
|
expect(injectError("Original message: {{error}}", "to inject")).toStrictEqual("Original message: to inject");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("missing error placeholder in the original message", () => {
|
||||||
|
expect(injectError("Original message: {{wrong}}", "to inject")).toStrictEqual("Original message: {{wrong}}");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("properly inject target branch into message", () => {
|
||||||
|
expect(injectTargetBranch("Original message: {{target-branch}}", "to inject")).toStrictEqual("Original message: to inject");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("missing target branch placeholder in the original message", () => {
|
||||||
|
expect(injectTargetBranch("Original message: {{wrong}}", "to inject")).toStrictEqual("Original message: {{wrong}}");
|
||||||
|
});
|
||||||
|
});
|
2004
test/support/mock/codeberg-data.ts
Normal file
2004
test/support/mock/codeberg-data.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,8 @@
|
||||||
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 { TARGET_OWNER, REPO, MERGED_PR_FIXTURE, OPEN_PR_FIXTURE, NOT_MERGED_PR_FIXTURE, NOT_FOUND_PR_NUMBER, MULT_COMMITS_PR_FIXTURE, MULT_COMMITS_PR_COMMITS, NEW_PR_URL, NEW_PR_NUMBER } from "./github-data";
|
import { TARGET_OWNER, REPO, MERGED_PR_FIXTURE, OPEN_PR_FIXTURE, NOT_MERGED_PR_FIXTURE, NOT_FOUND_PR_NUMBER, MULT_COMMITS_PR_FIXTURE, MULT_COMMITS_PR_COMMITS, NEW_PR_URL, NEW_PR_NUMBER, GITHUB_GET_COMMIT } from "./github-data";
|
||||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, NESTED_NAMESPACE_MR, OPEN_MR, OPEN_PR_COMMITS, PROJECT_EXAMPLE, NESTED_PROJECT_EXAMPLE, SUPERUSER, MERGED_SQUASHED_MR_COMMITS } from "./gitlab-data";
|
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, NESTED_NAMESPACE_MR, OPEN_MR, OPEN_PR_COMMITS, PROJECT_EXAMPLE, NESTED_PROJECT_EXAMPLE, SUPERUSER, MERGED_SQUASHED_MR_COMMITS, MERGED_NOT_SQUASHED_MR, MERGED_NOT_SQUASHED_MR_COMMITS } from "./gitlab-data";
|
||||||
|
import { CB_TARGET_OWNER, CB_REPO, CB_MERGED_PR_FIXTURE, CB_OPEN_PR_FIXTURE, CB_NOT_MERGED_PR_FIXTURE, CB_NOT_FOUND_PR_NUMBER, CB_MULT_COMMITS_PR_FIXTURE, CB_MULT_COMMITS_PR_COMMITS, CB_NEW_PR_URL, CB_NEW_PR_NUMBER, CODEBERG_GET_COMMIT } from "./codeberg-data";
|
||||||
|
|
||||||
// high number, for each test we are not expecting
|
// high number, for each test we are not expecting
|
||||||
// to send more than 3 reqs per api endpoint
|
// to send more than 3 reqs per api endpoint
|
||||||
|
@ -24,6 +25,8 @@ export const getAxiosMocked = (url: string) => {
|
||||||
data = CLOSED_NOT_MERGED_MR;
|
data = CLOSED_NOT_MERGED_MR;
|
||||||
} else if (url.endsWith("merge_requests/4")) {
|
} else if (url.endsWith("merge_requests/4")) {
|
||||||
data = NESTED_NAMESPACE_MR;
|
data = NESTED_NAMESPACE_MR;
|
||||||
|
} else if (url.endsWith("merge_requests/5")) {
|
||||||
|
data = MERGED_NOT_SQUASHED_MR;
|
||||||
} else if (url.endsWith("projects/76316")) {
|
} else if (url.endsWith("projects/76316")) {
|
||||||
data = PROJECT_EXAMPLE;
|
data = PROJECT_EXAMPLE;
|
||||||
} else if (url.endsWith("projects/1645")) {
|
} else if (url.endsWith("projects/1645")) {
|
||||||
|
@ -34,6 +37,8 @@ export const getAxiosMocked = (url: string) => {
|
||||||
data = MERGED_SQUASHED_MR_COMMITS;
|
data = MERGED_SQUASHED_MR_COMMITS;
|
||||||
} else if (url.endsWith("merge_requests/2/commits")) {
|
} else if (url.endsWith("merge_requests/2/commits")) {
|
||||||
data = OPEN_PR_COMMITS;
|
data = OPEN_PR_COMMITS;
|
||||||
|
} else if (url.endsWith("merge_requests/5/commits")) {
|
||||||
|
data = MERGED_NOT_SQUASHED_MR_COMMITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -157,6 +162,17 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
data: MULT_COMMITS_PR_COMMITS
|
data: MULT_COMMITS_PR_COMMITS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.listCommits({
|
||||||
|
owner: TARGET_OWNER,
|
||||||
|
repo: REPO,
|
||||||
|
pull_number: OPEN_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: MULT_COMMITS_PR_COMMITS
|
||||||
|
});
|
||||||
|
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
.create()
|
.create()
|
||||||
.reply({
|
.reply({
|
||||||
|
@ -200,6 +216,17 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
data: {}
|
data: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mock.rest.git
|
||||||
|
.getCommit({
|
||||||
|
owner: TARGET_OWNER,
|
||||||
|
repo: REPO,
|
||||||
|
commit_sha: "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: GITHUB_GET_COMMIT,
|
||||||
|
});
|
||||||
|
|
||||||
// invalid requests
|
// invalid requests
|
||||||
mock.rest.pulls
|
mock.rest.pulls
|
||||||
.get({
|
.get({
|
||||||
|
@ -217,3 +244,151 @@ export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit =>
|
||||||
|
|
||||||
return mock;
|
return mock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// CODEBERG - OCTOKIT
|
||||||
|
|
||||||
|
export const mockCodebergClient = (apiUrl = "https://codeberg.org/api/v1"): Moctokit => {
|
||||||
|
logger.debug("Setting up moctokit..");
|
||||||
|
|
||||||
|
const mock = new Moctokit(apiUrl);
|
||||||
|
|
||||||
|
// setup the mock requests here
|
||||||
|
|
||||||
|
// valid requests
|
||||||
|
mock.rest.pulls
|
||||||
|
.get({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_MERGED_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_MERGED_PR_FIXTURE
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.get({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_MULT_COMMITS_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_MULT_COMMITS_PR_FIXTURE
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.get({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_OPEN_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_OPEN_PR_FIXTURE
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.get({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_NOT_MERGED_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_NOT_MERGED_PR_FIXTURE
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.listCommits({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_MULT_COMMITS_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_MULT_COMMITS_PR_COMMITS
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.listCommits({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_OPEN_PR_FIXTURE.number
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CB_MULT_COMMITS_PR_COMMITS
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.create()
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 201,
|
||||||
|
data: {
|
||||||
|
number: CB_NEW_PR_NUMBER,
|
||||||
|
html_url: CB_NEW_PR_URL,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.pulls
|
||||||
|
.requestReviewers()
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 201,
|
||||||
|
data: CB_MERGED_PR_FIXTURE
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.issues
|
||||||
|
.addAssignees()
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 201,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.issues
|
||||||
|
.addLabels()
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 200,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.issues
|
||||||
|
.createComment()
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 201,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.rest.git
|
||||||
|
.getCommit({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
commit_sha: "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
status: 200,
|
||||||
|
data: CODEBERG_GET_COMMIT,
|
||||||
|
});
|
||||||
|
|
||||||
|
// invalid requests
|
||||||
|
mock.rest.pulls
|
||||||
|
.get({
|
||||||
|
owner: CB_TARGET_OWNER,
|
||||||
|
repo: CB_REPO,
|
||||||
|
pull_number: CB_NOT_FOUND_PR_NUMBER
|
||||||
|
})
|
||||||
|
.reply({
|
||||||
|
repeat: REPEAT,
|
||||||
|
status: 404,
|
||||||
|
data: {
|
||||||
|
message: "Not found"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mock;
|
||||||
|
};
|
||||||
|
|
|
@ -96,8 +96,8 @@ export const MERGED_PR_FIXTURE = {
|
||||||
{
|
{
|
||||||
"id": 4901021057,
|
"id": 4901021057,
|
||||||
"node_id": "LA_kwDOImgs2354988AAAABJB-lgQ",
|
"node_id": "LA_kwDOImgs2354988AAAABJB-lgQ",
|
||||||
"url": "https://api.github.com/repos/owner/reponame/labels/original-label",
|
"url": "https://api.github.com/repos/owner/reponame/labels/backport-prod",
|
||||||
"name": "original-label",
|
"name": "backport prod",
|
||||||
"color": "AB975B",
|
"color": "AB975B",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -1431,7 +1431,33 @@ export const MULT_COMMITS_PR_FIXTURE = {
|
||||||
|
|
||||||
],
|
],
|
||||||
"labels": [
|
"labels": [
|
||||||
|
{
|
||||||
|
"id": 4901021057,
|
||||||
|
"node_id": "LA_kwDOImgs2354988AAAABJB-lgQ",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/labels/backport-v1",
|
||||||
|
"name": "backport v1",
|
||||||
|
"color": "AB975B",
|
||||||
|
"default": false,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4901021057,
|
||||||
|
"node_id": "LA_kwDOImgs2354988AAAABJB-lgQ",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/labels/backport-v2",
|
||||||
|
"name": "backport v2",
|
||||||
|
"color": "AB975B",
|
||||||
|
"default": false,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4901021057,
|
||||||
|
"node_id": "LA_kwDOImgs2354988AAAABJB-lgQ",
|
||||||
|
"url": "https://api.github.com/repos/owner/reponame/labels/backport-v3",
|
||||||
|
"name": "backport v3",
|
||||||
|
"color": "AB975B",
|
||||||
|
"default": false,
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"milestone": null,
|
"milestone": null,
|
||||||
"draft": false,
|
"draft": false,
|
||||||
|
@ -1806,6 +1832,14 @@ export const MULT_COMMITS_PR_FIXTURE = {
|
||||||
"changed_files": 2
|
"changed_files": 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const GITHUB_GET_COMMIT = {
|
||||||
|
"parents": [
|
||||||
|
{
|
||||||
|
"sha": "SHA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
export const MULT_COMMITS_PR_COMMITS = [
|
export const MULT_COMMITS_PR_COMMITS = [
|
||||||
{
|
{
|
||||||
"sha": "0404fb922ab75c3a8aecad5c97d9af388df04695",
|
"sha": "0404fb922ab75c3a8aecad5c97d9af388df04695",
|
||||||
|
|
|
@ -401,7 +401,7 @@ export const MERGED_SQUASHED_MR = {
|
||||||
"source_project_id":76316,
|
"source_project_id":76316,
|
||||||
"target_project_id":76316,
|
"target_project_id":76316,
|
||||||
"labels":[
|
"labels":[
|
||||||
"gitlab-original-label"
|
"backport-prod"
|
||||||
],
|
],
|
||||||
"draft":false,
|
"draft":false,
|
||||||
"work_in_progress":false,
|
"work_in_progress":false,
|
||||||
|
@ -755,6 +755,29 @@ export const OPEN_PR_COMMITS = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const MERGED_NOT_SQUASHED_MR_COMMITS = [
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
@ -898,3 +921,138 @@ export const NESTED_NAMESPACE_MR = {
|
||||||
"can_merge":true
|
"can_merge":true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MERGED_NOT_SQUASHED_MR = {
|
||||||
|
"id":807106,
|
||||||
|
"iid":1,
|
||||||
|
"project_id":76316,
|
||||||
|
"title":"Update test.txt",
|
||||||
|
"description":"This is the body",
|
||||||
|
"state":"merged",
|
||||||
|
"created_at":"2023-06-28T14:32:40.943Z",
|
||||||
|
"updated_at":"2023-06-28T14:37:12.108Z",
|
||||||
|
"merged_by":{
|
||||||
|
"id":14041,
|
||||||
|
"username":"superuser",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
},
|
||||||
|
"merge_user":{
|
||||||
|
"id":14041,
|
||||||
|
"username":"superuser",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
},
|
||||||
|
"merged_at":"2023-06-28T14:37:11.667Z",
|
||||||
|
"closed_by":null,
|
||||||
|
"closed_at":null,
|
||||||
|
"target_branch":"main",
|
||||||
|
"source_branch":"feature",
|
||||||
|
"user_notes_count":0,
|
||||||
|
"upvotes":0,
|
||||||
|
"downvotes":0,
|
||||||
|
"author":{
|
||||||
|
"id":14041,
|
||||||
|
"username":"superuser",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
},
|
||||||
|
"assignees":[
|
||||||
|
{
|
||||||
|
"id":14041,
|
||||||
|
"username":"superuser",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignee":{
|
||||||
|
"id":14041,
|
||||||
|
"username":"superuser",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
},
|
||||||
|
"reviewers":[
|
||||||
|
{
|
||||||
|
"id":1404188,
|
||||||
|
"username":"superuser1",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":1404199,
|
||||||
|
"username":"superuser2",
|
||||||
|
"name":"Super User",
|
||||||
|
"state":"active",
|
||||||
|
"avatar_url":"https://my.gitlab.host.com/uploads/-/system/user/avatar/14041/avatar.png",
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source_project_id":76316,
|
||||||
|
"target_project_id":76316,
|
||||||
|
"labels":[
|
||||||
|
"backport-prod"
|
||||||
|
],
|
||||||
|
"draft":false,
|
||||||
|
"work_in_progress":false,
|
||||||
|
"milestone":null,
|
||||||
|
"merge_when_pipeline_succeeds":false,
|
||||||
|
"merge_status":"can_be_merged",
|
||||||
|
"detailed_merge_status":"not_open",
|
||||||
|
"sha":"9e15674ebd48e05c6e428a1fa31dbb60a778d644",
|
||||||
|
"merge_commit_sha":"4d369c3e9a8d1d5b7e56c892a8ab2a7666583ac3",
|
||||||
|
"squash_commit_sha":null,
|
||||||
|
"discussion_locked":null,
|
||||||
|
"should_remove_source_branch":true,
|
||||||
|
"force_remove_source_branch":true,
|
||||||
|
"reference":"!5",
|
||||||
|
"references":{
|
||||||
|
"short":"!5",
|
||||||
|
"relative":"!5",
|
||||||
|
"full":"superuser/backporting-example!5"
|
||||||
|
},
|
||||||
|
"web_url":"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/5",
|
||||||
|
"time_stats":{
|
||||||
|
"time_estimate":0,
|
||||||
|
"total_time_spent":0,
|
||||||
|
"human_time_estimate":null,
|
||||||
|
"human_total_time_spent":null
|
||||||
|
},
|
||||||
|
"squash":false,
|
||||||
|
"squash_on_merge":false,
|
||||||
|
"task_completion_status":{
|
||||||
|
"count":0,
|
||||||
|
"completed_count":0
|
||||||
|
},
|
||||||
|
"has_conflicts":false,
|
||||||
|
"blocking_discussions_resolved":true,
|
||||||
|
"approvals_before_merge":null,
|
||||||
|
"subscribed":true,
|
||||||
|
"changes_count":"1",
|
||||||
|
"latest_build_started_at":null,
|
||||||
|
"latest_build_finished_at":null,
|
||||||
|
"first_deployed_to_production_at":null,
|
||||||
|
"pipeline":null,
|
||||||
|
"head_pipeline":null,
|
||||||
|
"diff_refs":{
|
||||||
|
"base_sha":"2c553a0c4c133a51806badce5fa4842b7253cb3b",
|
||||||
|
"head_sha":"9e15674ebd48e05c6e428a1fa31dbb60a778d644",
|
||||||
|
"start_sha":"2c553a0c4c133a51806badce5fa4842b7253cb3b"
|
||||||
|
},
|
||||||
|
"merge_error":null,
|
||||||
|
"first_contribution":false,
|
||||||
|
"user":{
|
||||||
|
"can_merge":true
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue