mirror of
https://code.forgejo.org/actions/git-backporting.git
synced 2025-02-22 10:35:43 -05:00
feat: integrate tool with gitlab service (#39)
* feat: integrate tool with gitlab service Fix https://github.com/lampajr/backporting/issues/30
This commit is contained in:
parent
8a007941d1
commit
107f5e52d6
35 changed files with 17821 additions and 1553 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -6,7 +6,8 @@ test/**/_temp/**/*
|
|||
yarn.lock
|
||||
coverage/
|
||||
test-report.xml
|
||||
report.json
|
||||
.idea/
|
||||
.vscode/
|
||||
build/
|
||||
# dist/
|
||||
# dist/
|
||||
|
|
33
README.md
33
README.md
|
@ -15,7 +15,7 @@
|
|||
|
||||
---
|
||||
|
||||
**BPer** is a [NodeJS](https://nodejs.org/) command line tool that provides capabilities to *backport* [1] pull requests in an automated way. This tool also comes with a predefined GitHub action in order to make CI/CD integration easier for all users.
|
||||
**Git Backporter**, also referenced as **bper**, is a [NodeJS](https://nodejs.org/) command line tool that provides capabilities to *backport* [1] pull requests (on *GitHub*) and merge requests (on *GitLab*) in an automated way. This tool also comes with a predefined *GitHub* action in order to make CI/CD integration easier for all users.
|
||||
|
||||
[1] *backporting* is an action aiming to move a change (usually a commit) from a branch (usually the main one) to another one, which is generally referring to a still maintained release branch. Keeping it simple: it is about to move a specific change or a set of them from one branch to another.
|
||||
|
||||
|
@ -23,12 +23,12 @@ Table of content
|
|||
----------------
|
||||
|
||||
* **[Usage](#usage)**
|
||||
* **[Supported Git Services](#supported-git-services)**
|
||||
* **[GitHub Action](#github-action)**
|
||||
* **[Limitations](#limitations)**
|
||||
* **[Contributions](#contributing)**
|
||||
* **[License](#license)**
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
This tool is released on the [public npm registry](https://www.npmjs.com/), therefore it can be easily installed using `npm`:
|
||||
|
@ -40,7 +40,7 @@ $ npm install -g @lampajr/bper
|
|||
Then it can be used as any other command line tool:
|
||||
|
||||
```bash
|
||||
$ bper -tb <branch> -pr <pull-request-url> -a <github-token> [-f <your-folder>]
|
||||
$ bper -tb <branch> -pr <pull-request-url> -a <git-token> [-f <your-folder>]
|
||||
```
|
||||
|
||||
### Inputs
|
||||
|
@ -66,10 +66,18 @@ This toold comes with some inputs that allow users to override the default behav
|
|||
| Backport Branch Name | --bp-branch-name | N | Name of the backporting pull request branch | bp-{target-branch}-{sha} |
|
||||
| Dry Run | -d, --dry-run | N | If enabled the tool does not push nor create anything remotely, use this to skip PR creation | false |
|
||||
|
||||
## Supported Git Services
|
||||
|
||||
Right now **bper** supports the following git management services:
|
||||
* ***GITHUB***: Introduced since the first release of this tool (version `1.0.0`). The interaction with this system is performed using [*octokit*](https://octokit.github.io/rest.js) client library.
|
||||
|
||||
* ***GITLAB***: This has been introduced since version `3.0.0`, it works for both public and private *GitLab* servers. The interaction with this service is performed using plain [*axios*](https://axios-http.com) requests. The *gitlab* api version that is used to make requests is `v4`, at the moment there is no possibility to override it.
|
||||
|
||||
> **NOTE**: by default, all gitlab requests are performed setting `rejectUnauthorized=false`, planning to make this configurable too.
|
||||
|
||||
## GitHub Action
|
||||
|
||||
This action can be used in any GitHub workflow, below you can find a simple example of manually triggered workflow backporting a specific pull request (provided as input).
|
||||
This action can be used in any *GitHub* workflow, below you can find a simple example of manually triggered workflow backporting a specific pull request (provided as input).
|
||||
|
||||
```yml
|
||||
name: Pull Request Backporting using BPer
|
||||
|
@ -145,25 +153,20 @@ jobs:
|
|||
|
||||
For a complete description of all inputs see [Inputs section](#inputs).
|
||||
|
||||
## Limitations
|
||||
## Future Works
|
||||
|
||||
**BPer** is in development mode, this means that it has many limitations right now. I'll try to summarize the most importan ones:
|
||||
**BPer** is still in development mode, this means that there are still many future works and extension. I'll try to summarize the most important ones:
|
||||
|
||||
- You can backport pull requests only.
|
||||
- It only works for [GitHub](https://github.com/).
|
||||
- Integrated in GitHub Actions CI/CD only.
|
||||
|
||||
Based on these limitations, the next **Future Works** could be the following:
|
||||
- Provide a way to backport single commit too (or a set of them), even if no original pull request is present.
|
||||
- Integrate this tool with other git management services (like GitLab and Bitbucket) to make it as generic as possible.
|
||||
- Integrate it into other CI/CD services like gitlab CI (once GitLab will be integrated as well).
|
||||
- Provide some reusable GitHub workflows.
|
||||
- Integrate this tool with other git management services (like Bitbucket) to make it as generic as possible.
|
||||
- Integrate it into other CI/CD services like gitlab CI.
|
||||
- Provide some reusable *GitHub* workflows.
|
||||
|
||||
## Contributing
|
||||
|
||||
This is an open source project, and you are more than welcome to contribute :heart:!
|
||||
|
||||
Every change must be submitted through a GitHub pull request (PR). Backporting uses continuous integration (CI). The CI runs checks against your branch after you submit the PR to ensure that your PR doesn’t introduce errors. If the CI identifies a potential problem, our friendly PR maintainers will help you resolve it.
|
||||
Every change must be submitted through a *GitHub* pull request (PR). Backporting uses continuous integration (CI). The CI runs checks against your branch after you submit the PR to ensure that your PR doesn’t introduce errors. If the CI identifies a potential problem, our friendly PR maintainers will help you resolve it.
|
||||
|
||||
> **Note**: this project follows [git-conventional-commits](https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13) standards, thanks to the [commit-msg hook](./.husky/commit-msg) you are not allowed to use commits that do not follow those standards.
|
||||
|
||||
|
|
7045
dist/cli/index.js
vendored
7045
dist/cli/index.js
vendored
File diff suppressed because one or more lines are too long
7035
dist/gha/index.js
vendored
7035
dist/gha/index.js
vendored
File diff suppressed because one or more lines are too long
2445
package-lock.json
generated
2445
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -45,6 +45,7 @@
|
|||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.4.0",
|
||||
"@commitlint/config-conventional": "^17.4.0",
|
||||
"@gitbeaker/rest": "^39.1.0",
|
||||
"@kie/mock-github": "^1.1.0",
|
||||
"@release-it/conventional-changelog": "^5.1.1",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
|
@ -55,11 +56,11 @@
|
|||
"@vercel/ncc": "^0.36.0",
|
||||
"eslint": "^8.30.0",
|
||||
"husky": "^8.0.2",
|
||||
"jest": "^29.3.1",
|
||||
"jest": "^29.0.0",
|
||||
"jest-sonar-reporter": "^2.0.0",
|
||||
"release-it": "^15.6.0",
|
||||
"semver": "^7.3.8",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-jest": "^29.0.0",
|
||||
"ts-node": "^10.8.1",
|
||||
"tsc-alias": "^1.8.2",
|
||||
"tsconfig-paths": "^4.1.0",
|
||||
|
@ -69,8 +70,10 @@
|
|||
"@actions/core": "^1.10.0",
|
||||
"@octokit/rest": "^18.12.0",
|
||||
"@octokit/webhooks-types": "^6.8.0",
|
||||
"axios": "^1.4.0",
|
||||
"commander": "^9.3.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"https": "^1.0.0",
|
||||
"simple-git": "^3.15.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import LoggerServiceFactory from "../logger/logger-service-factory";
|
|||
*/
|
||||
export default abstract class ConfigsParser {
|
||||
|
||||
private readonly logger: LoggerService;
|
||||
protected readonly logger: LoggerService;
|
||||
|
||||
constructor() {
|
||||
this.logger = LoggerServiceFactory.getLogger();
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
import { Args } from "@bp/service/args/args.types";
|
||||
import ConfigsParser from "@bp/service/configs/configs-parser";
|
||||
import { Configs } from "@bp/service/configs/configs.types";
|
||||
import GitService from "@bp/service/git/git-service";
|
||||
import GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import GitClient from "@bp/service/git/git-client";
|
||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { GitPullRequest } from "@bp/service/git/git.types";
|
||||
|
||||
export default class PullRequestConfigsParser extends ConfigsParser {
|
||||
|
||||
private gitService: GitService;
|
||||
private gitService: GitClient;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.gitService = GitServiceFactory.getService();
|
||||
this.gitService = GitClientFactory.getClient();
|
||||
}
|
||||
|
||||
public async parse(args: Args): Promise<Configs> {
|
||||
const pr: GitPullRequest = await this.gitService.getPullRequestFromUrl(args.pullRequest);
|
||||
let pr: GitPullRequest;
|
||||
try {
|
||||
pr = await this.gitService.getPullRequestFromUrl(args.pullRequest);
|
||||
} catch(error) {
|
||||
this.logger.error("Something went wrong retrieving pull request");
|
||||
throw error;
|
||||
}
|
||||
|
||||
const folder: string = args.folder ?? this.getDefaultFolder();
|
||||
|
||||
return {
|
||||
|
|
56
src/service/git/git-client-factory.ts
Normal file
56
src/service/git/git-client-factory.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import GitClient from "@bp/service/git/git-client";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
import GitHubService from "@bp/service/git/github/github-client";
|
||||
import LoggerService from "@bp/service/logger/logger-service";
|
||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import GitLabClient from "./gitlab/gitlab-client";
|
||||
|
||||
/**
|
||||
* Singleton git service factory class
|
||||
*/
|
||||
export default class GitClientFactory {
|
||||
|
||||
private static logger: LoggerService = LoggerServiceFactory.getLogger();
|
||||
private static instance?: GitClient;
|
||||
|
||||
public static getClient(): GitClient {
|
||||
if (!GitClientFactory.instance) {
|
||||
throw new Error("You must call `getOrCreate` method first!");
|
||||
}
|
||||
|
||||
return GitClientFactory.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the singleton git management service
|
||||
* @param type git management service type
|
||||
* @param authToken authentication token, like github/gitlab token
|
||||
*/
|
||||
public static getOrCreate(type: GitClientType, authToken: string, apiUrl: string): GitClient {
|
||||
|
||||
if (GitClientFactory.instance) {
|
||||
GitClientFactory.logger.warn("Git service already initialized!");
|
||||
return GitClientFactory.instance;
|
||||
}
|
||||
|
||||
this.logger.debug(`Setting up ${type} client: apiUrl=${apiUrl}, token=****`);
|
||||
|
||||
switch(type) {
|
||||
case GitClientType.GITHUB:
|
||||
GitClientFactory.instance = new GitHubService(authToken, apiUrl);
|
||||
break;
|
||||
case GitClientType.GITLAB:
|
||||
GitClientFactory.instance = new GitLabClient(authToken, apiUrl);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid git service type received: ${type}`);
|
||||
}
|
||||
|
||||
return GitClientFactory.instance;
|
||||
}
|
||||
|
||||
public static reset(): void {
|
||||
GitClientFactory.logger.warn("Resetting git service!");
|
||||
GitClientFactory.instance = undefined;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
|||
* Git management service interface, which provides a common API for interacting
|
||||
* with several git management services like GitHub, Gitlab or Bitbucket.
|
||||
*/
|
||||
export default interface GitService {
|
||||
export default interface GitClient {
|
||||
|
||||
// READ
|
||||
|
||||
|
@ -29,6 +29,7 @@ import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
|||
/**
|
||||
* Create a new pull request on the underneath git service
|
||||
* @param backport backport pull request data
|
||||
* @returns {Promise<string>} the pull request url
|
||||
*/
|
||||
createPullRequest(backport: BackportPullRequest): Promise<void>;
|
||||
createPullRequest(backport: BackportPullRequest): Promise<string>;
|
||||
}
|
20
src/service/git/git-mapper.ts
Normal file
20
src/service/git/git-mapper.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { GitPullRequest, GitRepoState, GitRepository } from "@bp/service/git/git.types";
|
||||
|
||||
/**
|
||||
* Generic git client response mapper
|
||||
*
|
||||
* PR - full pull request schema type
|
||||
* S - pull request state type
|
||||
*/
|
||||
export default interface GitResponseMapper<PR, S> {
|
||||
|
||||
mapPullRequest(
|
||||
pr: PR,
|
||||
): Promise<GitPullRequest>;
|
||||
|
||||
mapGitState(state: S): GitRepoState;
|
||||
|
||||
mapSourceRepo(pull: PR): Promise<GitRepository>;
|
||||
|
||||
mapTargetRepo (pull: PR): Promise<GitRepository>;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
import GitService from "@bp/service/git/git-service";
|
||||
import { GitServiceType } from "@bp/service/git/git.types";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import LoggerService from "@bp/service/logger/logger-service";
|
||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
|
||||
/**
|
||||
* Singleton git service factory class
|
||||
*/
|
||||
export default class GitServiceFactory {
|
||||
|
||||
private static logger: LoggerService = LoggerServiceFactory.getLogger();
|
||||
private static instance?: GitService;
|
||||
|
||||
public static getService(): GitService {
|
||||
if (!GitServiceFactory.instance) {
|
||||
throw new Error("You must call `init` method first!");
|
||||
}
|
||||
|
||||
return GitServiceFactory.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the singleton git management service
|
||||
* @param type git management service type
|
||||
* @param auth authentication, like github token
|
||||
*/
|
||||
public static getOrCreate(type: GitServiceType, auth: string): void {
|
||||
|
||||
if (GitServiceFactory.instance) {
|
||||
GitServiceFactory.logger.warn("Git service already initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case GitServiceType.GITHUB:
|
||||
GitServiceFactory.instance = new GitHubService(auth);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid git service type received: ${type}`);
|
||||
}
|
||||
}
|
||||
}
|
39
src/service/git/git-util.ts
Normal file
39
src/service/git/git-util.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
|
||||
const PUBLIC_GITHUB_URL = "https://github.com";
|
||||
const PUBLIC_GITHUB_API = "https://api.github.com";
|
||||
|
||||
/**
|
||||
* Infer the remote GIT service to interact with based on the provided
|
||||
* pull request URL
|
||||
* @param prUrl provided pull request URL
|
||||
* @returns {GitClientType}
|
||||
*/
|
||||
export const inferGitClient = (prUrl: string): GitClientType => {
|
||||
const stdPrUrl = prUrl.toLowerCase().trim();
|
||||
|
||||
if (stdPrUrl.includes(GitClientType.GITHUB.toString())) {
|
||||
return GitClientType.GITHUB;
|
||||
} else if (stdPrUrl.includes(GitClientType.GITLAB.toString())) {
|
||||
return GitClientType.GITLAB;
|
||||
}
|
||||
|
||||
throw new Error(`Remote git service not recognized from pr url: ${prUrl}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Infer the host git service from the pull request url
|
||||
* @param prUrl pull/merge request url
|
||||
* @param apiVersion the api version, ignored in case of public github
|
||||
* @returns api URL like https://api.github.com or https://gitlab.com/api/v4
|
||||
*/
|
||||
export const inferGitApiUrl = (prUrl: string, apiVersion = "v4"): string => {
|
||||
const url = new URL(prUrl);
|
||||
const baseUrl = `${url.protocol}//${url.host}`;
|
||||
|
||||
if (baseUrl.includes(PUBLIC_GITHUB_URL)) {
|
||||
return PUBLIC_GITHUB_API;
|
||||
}
|
||||
|
||||
return `${baseUrl}/api/${apiVersion}`;
|
||||
};
|
|
@ -3,7 +3,7 @@ export interface GitPullRequest {
|
|||
author: string,
|
||||
url?: string,
|
||||
htmlUrl?: string,
|
||||
state?: "open" | "closed",
|
||||
state?: GitRepoState,
|
||||
merged?: boolean,
|
||||
mergedBy?: string,
|
||||
title: string,
|
||||
|
@ -35,6 +35,14 @@ export interface BackportPullRequest {
|
|||
branchName?: string,
|
||||
}
|
||||
|
||||
export enum GitServiceType {
|
||||
GITHUB = "github"
|
||||
export enum GitClientType {
|
||||
GITHUB = "github",
|
||||
GITLAB = "gitlab",
|
||||
}
|
||||
|
||||
export enum GitRepoState {
|
||||
OPEN = "open",
|
||||
CLOSED = "closed",
|
||||
LOCKED = "locked", // just on gitlab
|
||||
MERGED = "merged", // just on gitlab
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import GitService from "@bp/service/git/git-service";
|
||||
import GitClient from "@bp/service/git/git-client";
|
||||
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
|
||||
import GitHubMapper from "@bp/service/git/github/github-mapper";
|
||||
import OctokitFactory from "@bp/service/git/github/octokit-factory";
|
||||
|
@ -7,15 +7,17 @@ import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
|||
import { Octokit } from "@octokit/rest";
|
||||
import { PullRequest } from "@octokit/webhooks-types";
|
||||
|
||||
export default class GitHubService implements GitService {
|
||||
export default class GitHubClient implements GitClient {
|
||||
|
||||
private logger: LoggerService;
|
||||
private apiUrl: string;
|
||||
private octokit: Octokit;
|
||||
private mapper: GitHubMapper;
|
||||
|
||||
constructor(token: string) {
|
||||
constructor(token: string, apiUrl: string) {
|
||||
this.apiUrl = apiUrl;
|
||||
this.logger = LoggerServiceFactory.getLogger();
|
||||
this.octokit = OctokitFactory.getOctokit(token);
|
||||
this.octokit = OctokitFactory.getOctokit(token, this.apiUrl);
|
||||
this.mapper = new GitHubMapper();
|
||||
}
|
||||
|
||||
|
@ -33,13 +35,13 @@ export default class GitHubService implements GitService {
|
|||
}
|
||||
|
||||
async getPullRequestFromUrl(prUrl: string): Promise<GitPullRequest> {
|
||||
const {owner, project} = this.getRepositoryFromPrUrl(prUrl);
|
||||
return this.getPullRequest(owner, project, parseInt(prUrl.substring(prUrl.lastIndexOf("/") + 1, prUrl.length)));
|
||||
const { owner, project, id } = this.extractPullRequestData(prUrl);
|
||||
return this.getPullRequest(owner, project, id);
|
||||
}
|
||||
|
||||
// WRITE
|
||||
|
||||
async createPullRequest(backport: BackportPullRequest): Promise<void> {
|
||||
async createPullRequest(backport: BackportPullRequest): Promise<string> {
|
||||
this.logger.info(`Creating pull request ${backport.head} -> ${backport.base}.`);
|
||||
this.logger.info(`${JSON.stringify(backport, null, 2)}`);
|
||||
|
||||
|
@ -52,6 +54,10 @@ export default class GitHubService implements GitService {
|
|||
body: backport.body
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
throw new Error("Pull request creation failed");
|
||||
}
|
||||
|
||||
if (backport.reviewers.length > 0) {
|
||||
try {
|
||||
await this.octokit.pulls.requestReviewers({
|
||||
|
@ -77,6 +83,8 @@ export default class GitHubService implements GitService {
|
|||
this.logger.error(`Error setting assignees: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
return data.html_url;
|
||||
}
|
||||
|
||||
// UTILS
|
||||
|
@ -86,11 +94,12 @@ export default class GitHubService implements GitService {
|
|||
* @param prUrl pull request url
|
||||
* @returns {{owner: string, project: string}}
|
||||
*/
|
||||
private getRepositoryFromPrUrl(prUrl: string): {owner: string, project: string} {
|
||||
private extractPullRequestData(prUrl: string): {owner: string, project: string, id: number} {
|
||||
const elems: string[] = prUrl.split("/");
|
||||
return {
|
||||
owner: elems[elems.length - 4],
|
||||
project: elems[elems.length - 3]
|
||||
project: elems[elems.length - 3],
|
||||
id: parseInt(prUrl.substring(prUrl.lastIndexOf("/") + 1, prUrl.length)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,19 @@
|
|||
import { GitPullRequest } from "@bp/service/git/git.types";
|
||||
import { GitPullRequest, GitRepoState, GitRepository } from "@bp/service/git/git.types";
|
||||
import { PullRequest, User } from "@octokit/webhooks-types";
|
||||
import GitResponseMapper from "@bp/service/git/git-mapper";
|
||||
|
||||
export default class GitHubMapper {
|
||||
export default class GitHubMapper implements GitResponseMapper<PullRequest, "open" | "closed"> {
|
||||
|
||||
mapPullRequest(pr: PullRequest): GitPullRequest {
|
||||
mapGitState(state: "open" | "closed"): GitRepoState {
|
||||
switch (state) {
|
||||
case "open":
|
||||
return GitRepoState.OPEN;
|
||||
default:
|
||||
return GitRepoState.CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
async mapPullRequest(pr: PullRequest): Promise<GitPullRequest> {
|
||||
return {
|
||||
number: pr.number,
|
||||
author: pr.user.login,
|
||||
|
@ -11,24 +21,32 @@ export default class GitHubMapper {
|
|||
htmlUrl: pr.html_url,
|
||||
title: pr.title,
|
||||
body: pr.body ?? "",
|
||||
state: pr.state,
|
||||
state: this.mapGitState(pr.state), // TODO fix using custom mapper
|
||||
merged: pr.merged ?? false,
|
||||
mergedBy: pr.merged_by?.login,
|
||||
reviewers: pr.requested_reviewers.filter(r => "login" in r).map((r => (r as User)?.login)),
|
||||
assignees: pr.assignees.filter(r => "login" in r).map(r => r.login),
|
||||
sourceRepo: {
|
||||
owner: pr.head.repo.full_name.split("/")[0],
|
||||
project: pr.head.repo.full_name.split("/")[1],
|
||||
cloneUrl: pr.head.repo.clone_url
|
||||
},
|
||||
targetRepo: {
|
||||
owner: pr.base.repo.full_name.split("/")[0],
|
||||
project: pr.base.repo.full_name.split("/")[1],
|
||||
cloneUrl: pr.base.repo.clone_url
|
||||
},
|
||||
sourceRepo: await this.mapSourceRepo(pr),
|
||||
targetRepo: await this.mapTargetRepo(pr),
|
||||
nCommits: pr.commits,
|
||||
// if pr is open use latest commit sha otherwise use merge_commit_sha
|
||||
commits: pr.state === "open" ? [pr.head.sha] : [pr.merge_commit_sha as string]
|
||||
};
|
||||
}
|
||||
|
||||
async mapSourceRepo(pr: PullRequest): Promise<GitRepository> {
|
||||
return Promise.resolve({
|
||||
owner: pr.head.repo.full_name.split("/")[0],
|
||||
project: pr.head.repo.full_name.split("/")[1],
|
||||
cloneUrl: pr.head.repo.clone_url
|
||||
});
|
||||
}
|
||||
|
||||
async mapTargetRepo(pr: PullRequest): Promise<GitRepository> {
|
||||
return Promise.resolve({
|
||||
owner: pr.base.repo.full_name.split("/")[0],
|
||||
project: pr.base.repo.full_name.split("/")[1],
|
||||
cloneUrl: pr.base.repo.clone_url
|
||||
});
|
||||
}
|
||||
}
|
|
@ -10,12 +10,13 @@ export default class OctokitFactory {
|
|||
private static logger: LoggerService = LoggerServiceFactory.getLogger();
|
||||
private static octokit?: Octokit;
|
||||
|
||||
public static getOctokit(token: string): Octokit {
|
||||
public static getOctokit(token: string, apiUrl: string): Octokit {
|
||||
if (!OctokitFactory.octokit) {
|
||||
OctokitFactory.logger.info("Creating octokit instance.");
|
||||
OctokitFactory.octokit = new Octokit({
|
||||
auth: token,
|
||||
userAgent: "lampajr/backporting"
|
||||
userAgent: "lampajr/backporting",
|
||||
baseUrl: apiUrl
|
||||
});
|
||||
}
|
||||
|
||||
|
|
157
src/service/git/gitlab/gitlab-client.ts
Normal file
157
src/service/git/gitlab/gitlab-client.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
import LoggerService from "@bp/service/logger/logger-service";
|
||||
import GitClient from "@bp/service/git/git-client";
|
||||
import { GitPullRequest, BackportPullRequest } from "@bp/service/git/git.types";
|
||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { MergeRequestSchema, UserSchema } from "@gitbeaker/rest";
|
||||
import GitLabMapper from "@bp/service/git/gitlab/gitlab-mapper";
|
||||
import axios, { Axios } from "axios";
|
||||
import https from "https";
|
||||
|
||||
export default class GitLabClient implements GitClient {
|
||||
|
||||
private readonly logger: LoggerService;
|
||||
private readonly apiUrl: string;
|
||||
private readonly mapper: GitLabMapper;
|
||||
private readonly client: Axios;
|
||||
|
||||
constructor(token: string, apiUrl: string, rejectUnauthorized = false) {
|
||||
this.logger = LoggerServiceFactory.getLogger();
|
||||
this.apiUrl = apiUrl;
|
||||
this.client = axios.create({
|
||||
baseURL: this.apiUrl,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"User-Agent": "lampajr/backporting",
|
||||
},
|
||||
httpsAgent: new https.Agent({
|
||||
rejectUnauthorized
|
||||
})
|
||||
});
|
||||
this.mapper = new GitLabMapper(this.client);
|
||||
}
|
||||
|
||||
// READ
|
||||
|
||||
// example: <host>/api/v4/projects/alampare%2Fbackporting-example/merge_requests/1
|
||||
async getPullRequest(namespace: string, repo: string, mrNumber: number): Promise<GitPullRequest> {
|
||||
const projectId = this.getProjectId(namespace, repo);
|
||||
const { data } = await this.client.get(`/projects/${projectId}/merge_requests/${mrNumber}`);
|
||||
|
||||
return this.mapper.mapPullRequest(data as MergeRequestSchema);
|
||||
}
|
||||
|
||||
getPullRequestFromUrl(mrUrl: string): Promise<GitPullRequest> {
|
||||
const { namespace, project, id } = this.extractMergeRequestData(mrUrl);
|
||||
return this.getPullRequest(namespace, project, id);
|
||||
}
|
||||
|
||||
// WRITE
|
||||
|
||||
async createPullRequest(backport: BackportPullRequest): Promise<string> {
|
||||
this.logger.info(`Creating pull request ${backport.head} -> ${backport.base}.`);
|
||||
this.logger.info(`${JSON.stringify(backport, null, 2)}`);
|
||||
|
||||
const projectId = this.getProjectId(backport.owner, backport.repo);
|
||||
|
||||
const { data } = await this.client.post(`/projects/${projectId}/merge_requests`, {
|
||||
source_branch: backport.head,
|
||||
target_branch: backport.base,
|
||||
title: backport.title,
|
||||
description: backport.body,
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
});
|
||||
|
||||
const mr = data as MergeRequestSchema;
|
||||
|
||||
// reviewers
|
||||
const reviewerIds: number[] = [];
|
||||
for(const r of backport.reviewers) {
|
||||
try {
|
||||
this.logger.debug("Retrieving user: " + r);
|
||||
const user = await this.getUser(r);
|
||||
reviewerIds.push(user.id);
|
||||
} catch(error) {
|
||||
this.logger.warn(`Failed to retrieve reviewer ${r}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (reviewerIds.length > 0) {
|
||||
try {
|
||||
this.logger.info("Setting reviewers: " + reviewerIds);
|
||||
await this.client.put(`/projects/${projectId}/merge_requests/${mr.iid}`, {
|
||||
reviewer_ids: reviewerIds.filter(r => r !== undefined),
|
||||
});
|
||||
} catch(error) {
|
||||
this.logger.warn("Failure trying to update reviewers. " + error);
|
||||
}
|
||||
}
|
||||
|
||||
// assignees
|
||||
const assigneeIds: number[] = [];
|
||||
for(const a of backport.assignees) {
|
||||
try {
|
||||
this.logger.debug("Retrieving user: " + a);
|
||||
const user = await this.getUser(a);
|
||||
assigneeIds.push(user.id);
|
||||
} catch(error) {
|
||||
this.logger.warn(`Failed to retrieve assignee ${a}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (assigneeIds.length > 0) {
|
||||
try {
|
||||
this.logger.info("Setting assignees: " + assigneeIds);
|
||||
await this.client.put(`/projects/${projectId}/merge_requests/${mr.iid}`, {
|
||||
assignee_ids: assigneeIds.filter(a => a !== undefined),
|
||||
});
|
||||
} catch(error) {
|
||||
this.logger.warn("Failure trying to update assignees. " + error);
|
||||
}
|
||||
}
|
||||
|
||||
return mr.web_url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a gitlab user given its username
|
||||
* @param username
|
||||
* @returns UserSchema
|
||||
*/
|
||||
private async getUser(username: string): Promise<UserSchema> {
|
||||
const { data } = await this.client.get(`/users?username=${username}`);
|
||||
const users = data as UserSchema[];
|
||||
|
||||
if (users.length > 1) {
|
||||
throw new Error("Too many users found with username=" + username);
|
||||
}
|
||||
|
||||
if (users.length == 0) {
|
||||
throw new Error("User " + username + " not found");
|
||||
}
|
||||
|
||||
return users[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract repository namespace, project and mr number from the merge request url
|
||||
* example: <host>/alampare/backporting-example/-/merge_requests/1
|
||||
* note: "-/" could be omitted
|
||||
* @param mrUrl merge request url
|
||||
* @returns {{owner: string, project: string}}
|
||||
*/
|
||||
private extractMergeRequestData(mrUrl: string): {namespace: string, project: string, id: number} {
|
||||
const elems: string[] = mrUrl.replace("/-/", "/").split("/");
|
||||
return {
|
||||
namespace: elems[elems.length - 4],
|
||||
project: elems[elems.length - 3],
|
||||
id: parseInt(mrUrl.substring(mrUrl.lastIndexOf("/") + 1, mrUrl.length)),
|
||||
};
|
||||
}
|
||||
|
||||
private getProjectId(namespace: string, repo: string) {
|
||||
// e.g., <namespace>%2F<repo>
|
||||
return encodeURIComponent(`${namespace}/${repo}`);
|
||||
}
|
||||
}
|
83
src/service/git/gitlab/gitlab-mapper.ts
Normal file
83
src/service/git/gitlab/gitlab-mapper.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { GitPullRequest, GitRepoState, GitRepository } from "@bp/service/git/git.types";
|
||||
import GitResponseMapper from "@bp/service/git/git-mapper";
|
||||
import { MergeRequestSchema, ProjectSchema } from "@gitbeaker/rest";
|
||||
import { Axios } from "axios";
|
||||
|
||||
export default class GitLabMapper implements GitResponseMapper<MergeRequestSchema, string> {
|
||||
|
||||
private readonly client;
|
||||
// needs client to perform additional requests
|
||||
constructor(client: Axios) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
mapGitState(state: string): GitRepoState {
|
||||
switch (state) {
|
||||
case "opened":
|
||||
return GitRepoState.OPEN;
|
||||
case "closed":
|
||||
return GitRepoState.CLOSED;
|
||||
case "merged":
|
||||
return GitRepoState.MERGED;
|
||||
default:
|
||||
return GitRepoState.LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
async mapPullRequest(mr: MergeRequestSchema): Promise<GitPullRequest> {
|
||||
// throw new Error("Method not implemented.");
|
||||
return {
|
||||
number: mr.iid,
|
||||
author: mr.author.username,
|
||||
url: mr.web_url,
|
||||
htmlUrl: mr.web_url,
|
||||
title: mr.title,
|
||||
body: mr.description,
|
||||
state: this.mapGitState(mr.state),
|
||||
merged: this.isMerged(mr),
|
||||
mergedBy: mr.merged_by?.username,
|
||||
reviewers: mr.reviewers?.map((r => r.username)) ?? [],
|
||||
assignees: mr.assignees?.map((r => r.username)) ?? [],
|
||||
sourceRepo: await this.mapSourceRepo(mr),
|
||||
targetRepo: await this.mapTargetRepo(mr),
|
||||
nCommits: 1, // info not present on mr
|
||||
// if mr is merged, use merge_commit_sha otherwise use sha
|
||||
// what is the difference between sha and diff_refs.head_sha?
|
||||
commits: this.isMerged(mr) ? [mr.squash_commit_sha ? mr.squash_commit_sha : mr.merge_commit_sha as string] : [mr.sha]
|
||||
};
|
||||
}
|
||||
|
||||
async mapSourceRepo(mr: MergeRequestSchema): Promise<GitRepository> {
|
||||
const project: ProjectSchema = await this.getProject(mr.source_project_id);
|
||||
|
||||
return {
|
||||
owner: project.namespace.full_path, // or just proj.path?
|
||||
project: project.path,
|
||||
cloneUrl: project.http_url_to_repo,
|
||||
};
|
||||
}
|
||||
|
||||
async mapTargetRepo(mr: MergeRequestSchema): Promise<GitRepository> {
|
||||
const project: ProjectSchema = await this.getProject(mr.target_project_id);
|
||||
|
||||
return {
|
||||
owner: project.namespace.full_path, // or just proj.path?
|
||||
project: project.path,
|
||||
cloneUrl: project.http_url_to_repo,
|
||||
};
|
||||
}
|
||||
|
||||
private isMerged(mr: MergeRequestSchema) {
|
||||
return this.mapGitState(mr.state) === GitRepoState.MERGED;
|
||||
}
|
||||
|
||||
private async getProject(projectId: number): Promise<ProjectSchema> {
|
||||
const { data } = await this.client.get(`/projects/${projectId}`);
|
||||
|
||||
if (!data) {
|
||||
throw new Error(`Project ${projectId} not found`);
|
||||
}
|
||||
|
||||
return data as ProjectSchema;
|
||||
}
|
||||
}
|
|
@ -3,10 +3,12 @@ import LoggerService from "@bp/service/logger/logger-service";
|
|||
|
||||
export default class ConsoleLoggerService implements LoggerService {
|
||||
|
||||
private readonly logger;
|
||||
private readonly logger: Logger;
|
||||
private readonly verbose: boolean;
|
||||
|
||||
constructor() {
|
||||
constructor(verbose = true) {
|
||||
this.logger = new Logger();
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
trace(message: string): void {
|
||||
|
@ -14,7 +16,9 @@ export default class ConsoleLoggerService implements LoggerService {
|
|||
}
|
||||
|
||||
debug(message: string): void {
|
||||
this.logger.log("[DEBUG]", message);
|
||||
if (this.verbose) {
|
||||
this.logger.log("[DEBUG]", message);
|
||||
}
|
||||
}
|
||||
|
||||
info(message: string): void {
|
||||
|
|
|
@ -3,11 +3,12 @@ import { Args } from "@bp/service/args/args.types";
|
|||
import { Configs } from "@bp/service/configs/configs.types";
|
||||
import PullRequestConfigsParser from "@bp/service/configs/pullrequest/pr-configs-parser";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitService from "@bp/service/git/git-service";
|
||||
import GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import { BackportPullRequest, GitPullRequest, GitServiceType } from "@bp/service/git/git.types";
|
||||
import GitClient from "@bp/service/git/git-client";
|
||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
|
||||
import LoggerService from "@bp/service/logger/logger-service";
|
||||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { inferGitClient, inferGitApiUrl } from "@bp/service/git/git-util";
|
||||
|
||||
/**
|
||||
* Main runner implementation, it implements the core logic flow
|
||||
|
@ -22,22 +23,6 @@ export default class Runner {
|
|||
this.argsParser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer the remote GIT service to interact with based on the provided
|
||||
* pull request URL
|
||||
* @param prUrl provided pull request URL
|
||||
* @returns {GitServiceType}
|
||||
*/
|
||||
private inferRemoteGitService(prUrl: string): GitServiceType {
|
||||
const stdPrUrl = prUrl.toLowerCase().trim();
|
||||
|
||||
if (stdPrUrl.includes(GitServiceType.GITHUB.toString())) {
|
||||
return GitServiceType.GITHUB;
|
||||
}
|
||||
|
||||
throw new Error(`Remote GIT service not recognixed from PR url: ${prUrl}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point invoked by the command line or gha
|
||||
*/
|
||||
|
@ -69,10 +54,13 @@ export default class Runner {
|
|||
}
|
||||
|
||||
// 2. init git service
|
||||
GitServiceFactory.getOrCreate(this.inferRemoteGitService(args.pullRequest), args.auth);
|
||||
const gitApi: GitService = GitServiceFactory.getService();
|
||||
const gitClientType: GitClientType = inferGitClient(args.pullRequest);
|
||||
// right now the apiVersion is set to v4
|
||||
const apiUrl = inferGitApiUrl(args.pullRequest);
|
||||
const gitApi: GitClient = GitClientFactory.getOrCreate(gitClientType, args.auth, apiUrl);
|
||||
|
||||
// 3. parse configs
|
||||
this.logger.debug("Parsing configs..");
|
||||
const configs: Configs = await new PullRequestConfigsParser().parseAndValidate(args);
|
||||
const originalPR: GitPullRequest = configs.originalPullRequest;
|
||||
const backportPR: GitPullRequest = configs.backportPullRequest;
|
||||
|
@ -81,19 +69,24 @@ export default class Runner {
|
|||
const git: GitCLIService = new GitCLIService(configs.auth, configs.git);
|
||||
|
||||
// 4. clone the repository
|
||||
this.logger.debug("Cloning repo..");
|
||||
await git.clone(configs.originalPullRequest.targetRepo.cloneUrl, configs.folder, configs.targetBranch);
|
||||
|
||||
// 5. create new branch from target one and checkout
|
||||
this.logger.debug("Creating local branch..");
|
||||
const backportBranch = backportPR.branchName ?? `bp-${configs.targetBranch}-${originalPR.commits!.join("-")}`;
|
||||
await git.createLocalBranch(configs.folder, backportBranch);
|
||||
|
||||
// 6. fetch pull request remote if source owner != target owner or pull request still open
|
||||
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
|
||||
configs.originalPullRequest.state === "open") {
|
||||
await git.fetch(configs.folder, `pull/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
|
||||
this.logger.debug("Fetching pull request remote..");
|
||||
const prefix = gitClientType === GitClientType.GITHUB ? "pull" : "merge-requests"; // default is for gitlab
|
||||
await git.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
|
||||
}
|
||||
|
||||
// 7. apply all changes to the new branch
|
||||
this.logger.debug("Cherry picking commits..");
|
||||
for (const sha of originalPR.commits!) {
|
||||
await git.cherryPick(configs.folder, sha);
|
||||
}
|
||||
|
@ -114,7 +107,8 @@ export default class Runner {
|
|||
await git.push(configs.folder, backportBranch);
|
||||
|
||||
// 9. create pull request new branch -> target branch (using octokit)
|
||||
await gitApi.createPullRequest(backport);
|
||||
const prUrl = await gitApi.createPullRequest(backport);
|
||||
this.logger.info(`Pull request created: ${prUrl}`);
|
||||
|
||||
} else {
|
||||
this.logger.warn("Pull request creation and remote push skipped!");
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Args } from "@bp/service/args/args.types";
|
||||
import { Configs } from "@bp/service/configs/configs.types";
|
||||
import PullRequestConfigsParser from "@bp/service/configs/pullrequest/pr-configs-parser";
|
||||
import GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import { GitServiceType } from "@bp/service/git/git.types";
|
||||
import { setupMoctokit } from "../../../support/moctokit/moctokit-support";
|
||||
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner } from "../../../support/moctokit/moctokit-data";
|
||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
import { mockGitHubClient } from "../../../support/mock/git-client-mock-support";
|
||||
import { mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, repo, targetOwner } from "../../../support/mock/github-data";
|
||||
|
||||
describe("pull request config parser", () => {
|
||||
describe("github pull request config parser", () => {
|
||||
|
||||
const mergedPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${mergedPullRequestFixture.number}`;
|
||||
const openPRUrl = `https://github.com/${targetOwner}/${repo}/pull/${openPullRequestFixture.number}`;
|
||||
|
@ -15,11 +15,12 @@ describe("pull request config parser", () => {
|
|||
let parser: PullRequestConfigsParser;
|
||||
|
||||
beforeAll(() => {
|
||||
GitServiceFactory.getOrCreate(GitServiceType.GITHUB, "whatever");
|
||||
GitClientFactory.reset();
|
||||
GitClientFactory.getOrCreate(GitClientType.GITHUB, "whatever", "http://localhost/api/v3");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
mockGitHubClient("http://localhost/api/v3");
|
||||
|
||||
parser = new PullRequestConfigsParser();
|
||||
});
|
||||
|
@ -124,30 +125,6 @@ describe("pull request config parser", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("override author", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "GitHub",
|
||||
gitEmail: "noreply@github.com",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.git).toEqual({
|
||||
user: "GitHub",
|
||||
email: "noreply@github.com"
|
||||
});
|
||||
});
|
||||
|
||||
test("still open pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
|
@ -177,7 +154,7 @@ describe("pull request config parser", () => {
|
|||
htmlUrl: "https://github.com/owner/reponame/pull/4444",
|
||||
state: "open",
|
||||
merged: false,
|
||||
mergedBy: "that-s-a-user",
|
||||
mergedBy: undefined,
|
||||
title: "PR Title",
|
||||
body: "Please review and merge",
|
||||
reviewers: ["gh-user"],
|
|
@ -0,0 +1,420 @@
|
|||
import { Args } from "@bp/service/args/args.types";
|
||||
import { Configs } from "@bp/service/configs/configs.types";
|
||||
import PullRequestConfigsParser from "@bp/service/configs/pullrequest/pr-configs-parser";
|
||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
import { getAxiosMocked } from "../../../support/mock/git-client-mock-support";
|
||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR } from "../../../support/mock/gitlab-data";
|
||||
|
||||
jest.mock("axios", () => {
|
||||
return {
|
||||
create: jest.fn(() => ({
|
||||
get: getAxiosMocked,
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
describe("gitlab merge request config parser", () => {
|
||||
|
||||
const mergedPRUrl = `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${MERGED_SQUASHED_MR.iid}`;
|
||||
const openPRUrl = `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${OPEN_MR.iid}`;
|
||||
const notMergedPRUrl = `https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/${CLOSED_NOT_MERGED_MR.iid}`;
|
||||
|
||||
let parser: PullRequestConfigsParser;
|
||||
|
||||
beforeAll(() => {
|
||||
GitClientFactory.reset();
|
||||
GitClientFactory.getOrCreate(GitClientType.GITLAB, "whatever", "my.gitlab.host.com");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
parser = new PullRequestConfigsParser();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test("parse configs from merge request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: false,
|
||||
auth: "",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "GitLab",
|
||||
gitEmail: "noreply@gitlab.com",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(false);
|
||||
expect(configs.git).toEqual({
|
||||
user: "GitLab",
|
||||
email: "noreply@gitlab.com"
|
||||
});
|
||||
expect(configs.auth).toEqual("");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 1,
|
||||
author: "superuser",
|
||||
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
state: "merged",
|
||||
merged: true,
|
||||
mergedBy: "superuser",
|
||||
title: "Update test.txt",
|
||||
body: "This is the body",
|
||||
reviewers: ["superuser1", "superuser2"],
|
||||
assignees: ["superuser"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
nCommits: 1,
|
||||
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
|
||||
});
|
||||
expect(configs.backportPullRequest).toEqual({
|
||||
author: "GitLab",
|
||||
url: undefined,
|
||||
htmlUrl: undefined,
|
||||
title: "[prod] Update test.txt",
|
||||
body: "**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1\r\n\r\nThis is the body",
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
bpBranchName: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test("override folder", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
folder: "/tmp/test",
|
||||
gitUser: "GitLab",
|
||||
gitEmail: "noreply@gitlab.com",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual("/tmp/test");
|
||||
expect(configs.git).toEqual({
|
||||
user: "GitLab",
|
||||
email: "noreply@gitlab.com"
|
||||
});
|
||||
});
|
||||
|
||||
test("still open pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: openPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "GitLab",
|
||||
gitEmail: "noreply@gitlab.com",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(true);
|
||||
expect(configs.auth).toEqual("whatever");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.git).toEqual({
|
||||
user: "GitLab",
|
||||
email: "noreply@gitlab.com"
|
||||
});
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 2,
|
||||
author: "superuser",
|
||||
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
state: "open",
|
||||
merged: false,
|
||||
mergedBy: undefined,
|
||||
title: "Update test.txt opened",
|
||||
body: "Still opened mr body",
|
||||
reviewers: ["superuser"],
|
||||
assignees: ["superuser"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
bpBranchName: undefined,
|
||||
nCommits: 1,
|
||||
// taken from mr.sha
|
||||
commits: ["9e15674ebd48e05c6e428a1fa31dbb60a778d644"]
|
||||
});
|
||||
});
|
||||
|
||||
test("closed pull request", async () => {
|
||||
const args: Args = {
|
||||
dryRun: true,
|
||||
auth: "whatever",
|
||||
pullRequest: notMergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "GitLab",
|
||||
gitEmail: "noreply@gitlab.com",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
expect(async () => await parser.parseAndValidate(args)).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
|
||||
test("override backport pr data inherting reviewers", async () => {
|
||||
const args: Args = {
|
||||
dryRun: false,
|
||||
auth: "",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "Me",
|
||||
gitEmail: "me@email.com",
|
||||
title: "New Title",
|
||||
body: "New Body",
|
||||
bodyPrefix: "New Body Prefix -",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
inheritReviewers: true,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(false);
|
||||
expect(configs.git).toEqual({
|
||||
user: "Me",
|
||||
email: "me@email.com"
|
||||
});
|
||||
expect(configs.auth).toEqual("");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 1,
|
||||
author: "superuser",
|
||||
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
state: "merged",
|
||||
merged: true,
|
||||
mergedBy: "superuser",
|
||||
title: "Update test.txt",
|
||||
body: "This is the body",
|
||||
reviewers: ["superuser1", "superuser2"],
|
||||
assignees: ["superuser"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
nCommits: 1,
|
||||
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
|
||||
});
|
||||
expect(configs.backportPullRequest).toEqual({
|
||||
author: "Me",
|
||||
url: undefined,
|
||||
htmlUrl: undefined,
|
||||
title: "New Title",
|
||||
body: "New Body Prefix -New Body",
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
bpBranchName: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
test("override backport pr reviewers and assignees", async () => {
|
||||
const args: Args = {
|
||||
dryRun: false,
|
||||
auth: "",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "Me",
|
||||
gitEmail: "me@email.com",
|
||||
title: "New Title",
|
||||
body: "New Body",
|
||||
bodyPrefix: "New Body Prefix -",
|
||||
reviewers: ["user1", "user2"],
|
||||
assignees: ["user3", "user4"],
|
||||
inheritReviewers: true, // not taken into account
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(false);
|
||||
expect(configs.git).toEqual({
|
||||
user: "Me",
|
||||
email: "me@email.com"
|
||||
});
|
||||
expect(configs.auth).toEqual("");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 1,
|
||||
author: "superuser",
|
||||
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
state: "merged",
|
||||
merged: true,
|
||||
mergedBy: "superuser",
|
||||
title: "Update test.txt",
|
||||
body: "This is the body",
|
||||
reviewers: ["superuser1", "superuser2"],
|
||||
assignees: ["superuser"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
nCommits: 1,
|
||||
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
|
||||
});
|
||||
expect(configs.backportPullRequest).toEqual({
|
||||
author: "Me",
|
||||
url: undefined,
|
||||
htmlUrl: undefined,
|
||||
title: "New Title",
|
||||
body: "New Body Prefix -New Body",
|
||||
reviewers: ["user1", "user2"],
|
||||
assignees: ["user3", "user4"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
bpBranchName: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
test("override backport pr empty reviewers", async () => {
|
||||
const args: Args = {
|
||||
dryRun: false,
|
||||
auth: "",
|
||||
pullRequest: mergedPRUrl,
|
||||
targetBranch: "prod",
|
||||
gitUser: "Me",
|
||||
gitEmail: "me@email.com",
|
||||
title: "New Title",
|
||||
body: "New Body",
|
||||
bodyPrefix: "New Body Prefix -",
|
||||
reviewers: [],
|
||||
assignees: ["user3", "user4"],
|
||||
inheritReviewers: false,
|
||||
};
|
||||
|
||||
const configs: Configs = await parser.parseAndValidate(args);
|
||||
|
||||
expect(configs.dryRun).toEqual(false);
|
||||
expect(configs.git).toEqual({
|
||||
user: "Me",
|
||||
email: "me@email.com"
|
||||
});
|
||||
expect(configs.auth).toEqual("");
|
||||
expect(configs.targetBranch).toEqual("prod");
|
||||
expect(configs.folder).toEqual(process.cwd() + "/bp");
|
||||
expect(configs.originalPullRequest).toEqual({
|
||||
number: 1,
|
||||
author: "superuser",
|
||||
url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
htmlUrl: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
state: "merged",
|
||||
merged: true,
|
||||
mergedBy: "superuser",
|
||||
title: "Update test.txt",
|
||||
body: "This is the body",
|
||||
reviewers: ["superuser1", "superuser2"],
|
||||
assignees: ["superuser"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
nCommits: 1,
|
||||
commits: ["ebb1eca696c42fd067658bd9b5267709f78ef38e"]
|
||||
});
|
||||
expect(configs.backportPullRequest).toEqual({
|
||||
author: "Me",
|
||||
url: undefined,
|
||||
htmlUrl: undefined,
|
||||
title: "New Title",
|
||||
body: "New Body Prefix -New Body",
|
||||
reviewers: [],
|
||||
assignees: ["user3", "user4"],
|
||||
targetRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
sourceRepo: {
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
},
|
||||
bpBranchName: undefined,
|
||||
});
|
||||
});
|
||||
});
|
34
test/service/git/git-client-factory.test.ts
Normal file
34
test/service/git/git-client-factory.test.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
import GitHubClient from "@bp/service/git/github/github-client";
|
||||
import GitLabClient from "@bp/service/git/gitlab/gitlab-client";
|
||||
|
||||
describe("git client factory test", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// reset git service
|
||||
GitClientFactory.reset();
|
||||
});
|
||||
|
||||
test("correctly create github client", () => {
|
||||
const client = GitClientFactory.getOrCreate(GitClientType.GITHUB, "auth", "apiurl");
|
||||
expect(client).toBeInstanceOf(GitHubClient);
|
||||
});
|
||||
|
||||
test("correctly create gitlab client", () => {
|
||||
const client = GitClientFactory.getOrCreate(GitClientType.GITLAB, "auth", "apiurl");
|
||||
expect(client).toBeInstanceOf(GitLabClient);
|
||||
});
|
||||
|
||||
test("check get service github", () => {
|
||||
const create = GitClientFactory.getOrCreate(GitClientType.GITHUB, "auth", "apiurl");
|
||||
const get = GitClientFactory.getClient();
|
||||
expect(create).toStrictEqual(get);
|
||||
});
|
||||
|
||||
test("check get service gitlab", () => {
|
||||
const create = GitClientFactory.getOrCreate(GitClientType.GITLAB, "auth", "apiurl");
|
||||
const get = GitClientFactory.getClient();
|
||||
expect(create).toStrictEqual(get);
|
||||
});
|
||||
});
|
37
test/service/git/git-util.test.ts
Normal file
37
test/service/git/git-util.test.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { inferGitApiUrl, inferGitClient } from "@bp/service/git/git-util";
|
||||
import { GitClientType } from "@bp/service/git/git.types";
|
||||
|
||||
describe("check git utilities", () => {
|
||||
|
||||
test("check infer gitlab api", ()=> {
|
||||
expect(inferGitApiUrl("https://my.gitlab.awesome.com/superuser/backporting-example/-/merge_requests/4")).toStrictEqual("https://my.gitlab.awesome.com/api/v4");
|
||||
});
|
||||
|
||||
test("check infer gitlab api with different version", ()=> {
|
||||
expect(inferGitApiUrl("http://my.gitlab.awesome.com/superuser/backporting-example/-/merge_requests/4", "v2")).toStrictEqual("http://my.gitlab.awesome.com/api/v2");
|
||||
});
|
||||
|
||||
test("check infer github api", ()=> {
|
||||
expect(inferGitApiUrl("https://github.com/superuser/backporting-example/pull/4")).toStrictEqual("https://api.github.com");
|
||||
});
|
||||
|
||||
test("check infer custom github api", ()=> {
|
||||
expect(inferGitApiUrl("http://github.acme-inc.com/superuser/backporting-example/pull/4")).toStrictEqual("http://github.acme-inc.com/api/v4");
|
||||
});
|
||||
|
||||
test("check infer custom github api with different version", ()=> {
|
||||
expect(inferGitApiUrl("http://github.acme-inc.com/superuser/backporting-example/pull/4", "v3")).toStrictEqual("http://github.acme-inc.com/api/v3");
|
||||
});
|
||||
|
||||
test("check infer github client", ()=> {
|
||||
expect(inferGitClient("https://github.com/superuser/backporting-example/-/merge_requests/4")).toStrictEqual(GitClientType.GITHUB);
|
||||
});
|
||||
|
||||
test("check infer gitlab client", ()=> {
|
||||
expect(inferGitClient("https://my.gitlab.awesome.com/superuser/backporting-example/-/merge_requests/4")).toStrictEqual(GitClientType.GITLAB);
|
||||
});
|
||||
|
||||
test("Not recognized git client type", ()=> {
|
||||
expect(() => inferGitClient("https://not.recognized/superuser/backporting-example/-/merge_requests/4")).toThrowError("Remote git service not recognized from pr url: https://not.recognized/superuser/backporting-example/-/merge_requests/4");
|
||||
});
|
||||
});
|
|
@ -1,27 +1,28 @@
|
|||
import GitServiceFactory from "@bp/service/git/git-service-factory";
|
||||
import { GitPullRequest, GitServiceType } from "@bp/service/git/git.types";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import { mergedPullRequestFixture, repo, targetOwner } from "../../../support/moctokit/moctokit-data";
|
||||
import { setupMoctokit } from "../../../support/moctokit/moctokit-support";
|
||||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { GitPullRequest, GitClientType } from "@bp/service/git/git.types";
|
||||
import GitHubClient from "@bp/service/git/github/github-client";
|
||||
import { mergedPullRequestFixture, repo, targetOwner } from "../../../support/mock/github-data";
|
||||
import { mockGitHubClient } from "../../../support/mock/git-client-mock-support";
|
||||
|
||||
describe("github service", () => {
|
||||
|
||||
let gitService: GitHubService;
|
||||
let gitClient: GitHubClient;
|
||||
|
||||
beforeAll(() => {
|
||||
// init git service
|
||||
GitServiceFactory.getOrCreate(GitServiceType.GITHUB, "whatever");
|
||||
GitClientFactory.reset();
|
||||
GitClientFactory.getOrCreate(GitClientType.GITHUB, "whatever", "http://localhost/api/v3");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// mock github api calls
|
||||
setupMoctokit();
|
||||
mockGitHubClient("http://localhost/api/v3");
|
||||
|
||||
gitService = GitServiceFactory.getService() as GitHubService;
|
||||
gitClient = GitClientFactory.getClient() as GitHubClient;
|
||||
});
|
||||
|
||||
test("get pull request: success", async () => {
|
||||
const res: GitPullRequest = await gitService.getPullRequest(targetOwner, repo, mergedPullRequestFixture.number);
|
||||
const res: GitPullRequest = await gitClient.getPullRequest(targetOwner, repo, mergedPullRequestFixture.number);
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "fork",
|
||||
project: "reponame",
|
249
test/service/git/gitlab/gitlab-client.test.ts
Normal file
249
test/service/git/gitlab/gitlab-client.test.ts
Normal file
|
@ -0,0 +1,249 @@
|
|||
import GitClientFactory from "@bp/service/git/git-client-factory";
|
||||
import { NEW_GITLAB_MR_ID, SECOND_NEW_GITLAB_MR_ID, getAxiosMocked, postAxiosMocked, putAxiosMocked } from "../../../support/mock/git-client-mock-support";
|
||||
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
|
||||
import GitLabClient from "@bp/service/git/gitlab/gitlab-client";
|
||||
import axios from "axios";
|
||||
|
||||
jest.mock("axios");
|
||||
const axiosSpy = axios.create as jest.Mock;
|
||||
let axiosInstanceSpy: {[key: string]: jest.Func};
|
||||
|
||||
function setupAxiosSpy() {
|
||||
const getSpy = jest.fn(getAxiosMocked);
|
||||
const postSpy = jest.fn(postAxiosMocked);
|
||||
const putSpy = jest.fn(putAxiosMocked);
|
||||
const axiosInstance = {
|
||||
get: getSpy,
|
||||
post: postSpy,
|
||||
put: putSpy,
|
||||
};
|
||||
axiosSpy.mockImplementation(() => (axiosInstance));
|
||||
return axiosInstance;
|
||||
}
|
||||
|
||||
describe("github service", () => {
|
||||
let gitClient: GitLabClient;
|
||||
|
||||
beforeEach(() => {
|
||||
axiosInstanceSpy = setupAxiosSpy();
|
||||
GitClientFactory.reset();
|
||||
gitClient = GitClientFactory.getOrCreate(GitClientType.GITLAB, "whatever", "apiUrl") as GitLabClient;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test("get merged pull request", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 1);
|
||||
|
||||
// check content
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
});
|
||||
expect(res.targetRepo).toEqual({
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
});
|
||||
expect(res.title).toBe("Update test.txt");
|
||||
expect(res.commits!.length).toBe(1);
|
||||
expect(res.commits).toEqual(["ebb1eca696c42fd067658bd9b5267709f78ef38e"]);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(3); // merge request and 2 repos
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/1");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/76316");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/76316");
|
||||
});
|
||||
|
||||
test("get open pull request", async () => {
|
||||
const res: GitPullRequest = await gitClient.getPullRequest("superuser", "backporting-example", 2);
|
||||
expect(res.sourceRepo).toEqual({
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
});
|
||||
expect(res.targetRepo).toEqual({
|
||||
owner: "superuser",
|
||||
project: "backporting-example",
|
||||
cloneUrl: "https://my.gitlab.host.com/superuser/backporting-example.git"
|
||||
});
|
||||
expect(res.title).toBe("Update test.txt opened");
|
||||
expect(res.commits!.length).toBe(1);
|
||||
expect(res.commits).toEqual(["9e15674ebd48e05c6e428a1fa31dbb60a778d644"]);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(3); // merge request and 2 repos
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/2");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/76316");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/projects/76316");
|
||||
});
|
||||
|
||||
test("create backport pull request without reviewers and assignees", async () => {
|
||||
const backport: BackportPullRequest = {
|
||||
title: "Backport Title",
|
||||
body: "Backport Body",
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
base: "old/branch",
|
||||
head: "bp-branch",
|
||||
reviewers: [],
|
||||
assignees: [],
|
||||
};
|
||||
|
||||
const url: string = await gitClient.createPullRequest(backport);
|
||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||
source_branch: "bp-branch",
|
||||
target_branch: "old/branch",
|
||||
title: "Backport Title",
|
||||
description: "Backport Body",
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
}));
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(0); // no reviewers nor assignees
|
||||
expect(axiosInstanceSpy.put).toBeCalledTimes(0); // no reviewers nor assignees
|
||||
});
|
||||
|
||||
test("create backport pull request with reviewers", async () => {
|
||||
const backport: BackportPullRequest = {
|
||||
title: "Backport Title",
|
||||
body: "Backport Body",
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
base: "old/branch",
|
||||
head: "bp-branch",
|
||||
reviewers: ["superuser", "invalid"],
|
||||
assignees: [],
|
||||
};
|
||||
|
||||
const url: string = await gitClient.createPullRequest(backport);
|
||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||
source_branch: "bp-branch",
|
||||
target_branch: "old/branch",
|
||||
title: "Backport Title",
|
||||
description: "Backport Body",
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
}));
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(2); // just reviewers, one invalid
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=superuser");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=invalid");
|
||||
expect(axiosInstanceSpy.put).toBeCalledTimes(1); // just reviewers
|
||||
expect(axiosInstanceSpy.put).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + NEW_GITLAB_MR_ID, {
|
||||
reviewer_ids: [14041],
|
||||
});
|
||||
});
|
||||
|
||||
test("create backport pull request with assignees", async () => {
|
||||
const backport: BackportPullRequest = {
|
||||
title: "Backport Title",
|
||||
body: "Backport Body",
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
base: "old/branch",
|
||||
head: "bp-branch",
|
||||
reviewers: [],
|
||||
assignees: ["superuser", "invalid"],
|
||||
};
|
||||
|
||||
const url: string = await gitClient.createPullRequest(backport);
|
||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||
source_branch: "bp-branch",
|
||||
target_branch: "old/branch",
|
||||
title: "Backport Title",
|
||||
description: "Backport Body",
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
}));
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(2); // just assignees, one invalid
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=superuser");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=invalid");
|
||||
expect(axiosInstanceSpy.put).toBeCalledTimes(1); // just assignees
|
||||
expect(axiosInstanceSpy.put).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + NEW_GITLAB_MR_ID, {
|
||||
assignee_ids: [14041],
|
||||
});
|
||||
});
|
||||
|
||||
test("create backport pull request with failure assigning reviewers", async () => {
|
||||
const backport: BackportPullRequest = {
|
||||
title: "Backport Title",
|
||||
body: "Backport Body",
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
base: "old/branch",
|
||||
head: "bp-branch-2",
|
||||
reviewers: ["superuser", "invalid"],
|
||||
assignees: [],
|
||||
};
|
||||
|
||||
const url: string = await gitClient.createPullRequest(backport);
|
||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + SECOND_NEW_GITLAB_MR_ID);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||
source_branch: "bp-branch-2",
|
||||
target_branch: "old/branch",
|
||||
title: "Backport Title",
|
||||
description: "Backport Body",
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
}));
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(2); // just reviewers, one invalid
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=superuser");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=invalid");
|
||||
expect(axiosInstanceSpy.put).toBeCalledTimes(1); // just reviewers
|
||||
expect(axiosInstanceSpy.put).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + SECOND_NEW_GITLAB_MR_ID, {
|
||||
reviewer_ids: [14041],
|
||||
});
|
||||
});
|
||||
|
||||
test("create backport pull request with failure assigning assignees", async () => {
|
||||
const backport: BackportPullRequest = {
|
||||
title: "Backport Title",
|
||||
body: "Backport Body",
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
base: "old/branch",
|
||||
head: "bp-branch-2",
|
||||
reviewers: [],
|
||||
assignees: ["superuser", "invalid"],
|
||||
};
|
||||
|
||||
const url: string = await gitClient.createPullRequest(backport);
|
||||
expect(url).toStrictEqual("https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + SECOND_NEW_GITLAB_MR_ID);
|
||||
|
||||
// check axios invocation
|
||||
expect(axiosInstanceSpy.post).toBeCalledTimes(1);
|
||||
expect(axiosInstanceSpy.post).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests", expect.objectContaining({
|
||||
source_branch: "bp-branch-2",
|
||||
target_branch: "old/branch",
|
||||
title: "Backport Title",
|
||||
description: "Backport Body",
|
||||
reviewer_ids: [],
|
||||
assignee_ids: [],
|
||||
}));
|
||||
expect(axiosInstanceSpy.get).toBeCalledTimes(2); // just assignees, one invalid
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=superuser");
|
||||
expect(axiosInstanceSpy.get).toBeCalledWith("/users?username=invalid");
|
||||
expect(axiosInstanceSpy.put).toBeCalledTimes(1); // just assignees
|
||||
expect(axiosInstanceSpy.put).toBeCalledWith("/projects/superuser%2Fbackporting-example/merge_requests/" + SECOND_NEW_GITLAB_MR_ID, {
|
||||
assignee_ids: [14041],
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,19 +1,19 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import GitHubClient from "@bp/service/git/github/github-client";
|
||||
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
||||
import { addProcessArgs, resetProcessArgs } from "../../support/utils";
|
||||
import { setupMoctokit } from "../../support/moctokit/moctokit-support";
|
||||
import { mockGitHubClient } from "../../support/mock/git-client-mock-support";
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitHubService.prototype, "createPullRequest");
|
||||
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
mockGitHubClient();
|
||||
|
||||
// create CLI arguments parser
|
||||
parser = new CLIArgsParser();
|
||||
|
@ -30,6 +30,7 @@ afterEach(() => {
|
|||
});
|
||||
|
||||
describe("cli runner", () => {
|
||||
|
||||
test("with dry run", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
|
@ -56,7 +57,7 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("overriding author", async () => {
|
||||
|
@ -85,7 +86,7 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("with relative folder", async () => {
|
||||
|
@ -119,7 +120,7 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("with absolute folder", async () => {
|
||||
|
@ -150,7 +151,7 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
|
@ -180,8 +181,8 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
|
@ -220,8 +221,8 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
|
@ -272,15 +273,15 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-91748965051fae1330ad58d15cf694e103267c87",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/4444"),
|
||||
reviewers: ["gh-user", "that-s-a-user"],
|
||||
reviewers: ["gh-user"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
|
@ -325,8 +326,8 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp_branch_name",
|
||||
|
@ -377,8 +378,8 @@ describe("cli runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp_branch_name",
|
309
test/service/runner/cli-gitlab-runner.test.ts
Normal file
309
test/service/runner/cli-gitlab-runner.test.ts
Normal file
|
@ -0,0 +1,309 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitLabClient from "@bp/service/git/gitlab/gitlab-client";
|
||||
import CLIArgsParser from "@bp/service/args/cli/cli-args-parser";
|
||||
import { addProcessArgs, resetProcessArgs } from "../../support/utils";
|
||||
import { getAxiosMocked } from "../../support/mock/git-client-mock-support";
|
||||
|
||||
jest.mock("axios", () => {
|
||||
return {
|
||||
create: () => ({
|
||||
get: getAxiosMocked,
|
||||
post: () => ({
|
||||
data: {
|
||||
iid: 1, // FIXME: I am not testing this atm
|
||||
}
|
||||
}),
|
||||
put: jest.fn(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
||||
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
// create CLI arguments parser
|
||||
parser = new CLIArgsParser();
|
||||
|
||||
// create runner
|
||||
runner = new Runner(parser);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
// reset process.env variables
|
||||
resetProcessArgs();
|
||||
});
|
||||
|
||||
describe("cli runner", () => {
|
||||
|
||||
test("with dry run", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("dry run with relative folder", async () => {
|
||||
addProcessArgs([
|
||||
"-d",
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"-f",
|
||||
"folder"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/folder";
|
||||
|
||||
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-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||
expect(GitCLIService.prototype.addRemote).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp-target-9e15674ebd48e05c6e428a1fa31dbb60a778d644",
|
||||
base: "target",
|
||||
title: "[target] Update test.txt opened",
|
||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"),
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("closed and not merged pull request", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
||||
]);
|
||||
|
||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
|
||||
test("merged pull request", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
// 0 occurrences as the mr is already merged and the owner is the same for
|
||||
// both source and target repositories
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp-target-ebb1eca696c42fd067658bd9b5267709f78ef38e",
|
||||
base: "target",
|
||||
title: "[target] Update test.txt",
|
||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
test("override backporting pr data", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"--title",
|
||||
"New Title",
|
||||
"--body",
|
||||
"New Body",
|
||||
"--body-prefix",
|
||||
"New Body Prefix - ",
|
||||
"--bp-branch-name",
|
||||
"bp_branch_name",
|
||||
"--reviewers",
|
||||
"user1,user2",
|
||||
"--assignees",
|
||||
"user3,user4"
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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_branch_name");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp_branch_name",
|
||||
base: "target",
|
||||
title: "New Title",
|
||||
body: "New Body Prefix - New Body",
|
||||
reviewers: ["user1", "user2"],
|
||||
assignees: ["user3", "user4"],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("set empty reviewers", async () => {
|
||||
addProcessArgs([
|
||||
"-tb",
|
||||
"target",
|
||||
"-pr",
|
||||
"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"--title",
|
||||
"New Title",
|
||||
"--body",
|
||||
"New Body",
|
||||
"--body-prefix",
|
||||
"New Body Prefix - ",
|
||||
"--bp-branch-name",
|
||||
"bp_branch_name",
|
||||
"--no-inherit-reviewers",
|
||||
"--assignees",
|
||||
"user3,user4",
|
||||
]);
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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_branch_name");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp_branch_name",
|
||||
base: "target",
|
||||
title: "New Title",
|
||||
body: "New Body Prefix - New Body",
|
||||
reviewers: [],
|
||||
assignees: ["user3", "user4"],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,19 +1,19 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitHubService from "@bp/service/git/github/github-service";
|
||||
import GitHubClient from "@bp/service/git/github/github-client";
|
||||
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
||||
import { spyGetInput } from "../../support/utils";
|
||||
import { setupMoctokit } from "../../support/moctokit/moctokit-support";
|
||||
import { mockGitHubClient } from "../../support/mock/git-client-mock-support";
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitHubService.prototype, "createPullRequest");
|
||||
jest.spyOn(GitHubClient.prototype, "createPullRequest");
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
setupMoctokit();
|
||||
mockGitHubClient();
|
||||
|
||||
// create GHA arguments parser
|
||||
parser = new GHAArgsParser();
|
||||
|
@ -51,7 +51,7 @@ describe("gha runner", () => {
|
|||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
|
@ -79,8 +79,8 @@ describe("gha runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-28f63db774185f4ec4b57cd9aaeb12dbfb4c9ecc",
|
||||
|
@ -127,15 +127,15 @@ describe("gha runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-91748965051fae1330ad58d15cf694e103267c87");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp-target-91748965051fae1330ad58d15cf694e103267c87",
|
||||
base: "target",
|
||||
title: "[target] PR Title",
|
||||
body: expect.stringContaining("**Backport:** https://github.com/owner/reponame/pull/4444"),
|
||||
reviewers: ["gh-user", "that-s-a-user"],
|
||||
reviewers: ["gh-user"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
|
@ -172,8 +172,8 @@ describe("gha runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp_branch_name",
|
||||
|
@ -218,8 +218,8 @@ describe("gha runner", () => {
|
|||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubService.prototype.createPullRequest).toBeCalledWith({
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitHubClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "owner",
|
||||
repo: "reponame",
|
||||
head: "bp_branch_name",
|
245
test/service/runner/gha-gitlab-runner.test.ts
Normal file
245
test/service/runner/gha-gitlab-runner.test.ts
Normal file
|
@ -0,0 +1,245 @@
|
|||
import ArgsParser from "@bp/service/args/args-parser";
|
||||
import Runner from "@bp/service/runner/runner";
|
||||
import GitCLIService from "@bp/service/git/git-cli";
|
||||
import GitLabClient from "@bp/service/git/gitlab/gitlab-client";
|
||||
import GHAArgsParser from "@bp/service/args/gha/gha-args-parser";
|
||||
import { spyGetInput } from "../../support/utils";
|
||||
import { getAxiosMocked } from "../../support/mock/git-client-mock-support";
|
||||
|
||||
jest.mock("axios", () => {
|
||||
return {
|
||||
create: () => ({
|
||||
get: getAxiosMocked,
|
||||
post: () => ({
|
||||
data: {
|
||||
iid: 1, // FIXME: I am not testing this atm
|
||||
}
|
||||
}),
|
||||
put: jest.fn(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock("@bp/service/git/git-cli");
|
||||
jest.spyOn(GitLabClient.prototype, "createPullRequest");
|
||||
|
||||
let parser: ArgsParser;
|
||||
let runner: Runner;
|
||||
|
||||
beforeEach(() => {
|
||||
// create GHA arguments parser
|
||||
parser = new GHAArgsParser();
|
||||
|
||||
// create runner
|
||||
runner = new Runner(parser);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("gha runner", () => {
|
||||
test("with dry run", async () => {
|
||||
spyGetInput({
|
||||
"dry-run": "true",
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(0);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test("without dry run", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp-target-9e15674ebd48e05c6e428a1fa31dbb60a778d644",
|
||||
base: "target",
|
||||
title: "[target] Update test.txt opened",
|
||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2"),
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("closed and not merged pull request", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3"
|
||||
});
|
||||
|
||||
expect(async () => await runner.execute()).rejects.toThrow("Provided pull request is closed and not merged!");
|
||||
});
|
||||
|
||||
test("merged pull request", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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-ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(0);
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp-target-ebb1eca696c42fd067658bd9b5267709f78ef38e");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp-target-ebb1eca696c42fd067658bd9b5267709f78ef38e",
|
||||
base: "target",
|
||||
title: "[target] Update test.txt",
|
||||
body: expect.stringContaining("**Backport:** https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1"),
|
||||
reviewers: ["superuser"],
|
||||
assignees: [],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("override backporting pr data", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"title": "New Title",
|
||||
"body": "New Body",
|
||||
"body-prefix": "New Body Prefix - ",
|
||||
"bp-branch-name": "bp_branch_name",
|
||||
"reviewers": "user1, user2",
|
||||
"assignees": "user3, user4",
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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_branch_name");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp_branch_name",
|
||||
base: "target",
|
||||
title: "New Title",
|
||||
body: "New Body Prefix - New Body",
|
||||
reviewers: ["user1", "user2"],
|
||||
assignees: ["user3", "user4"],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("set empty reviewers", async () => {
|
||||
spyGetInput({
|
||||
"target-branch": "target",
|
||||
"pull-request": "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"title": "New Title",
|
||||
"body": "New Body",
|
||||
"body-prefix": "New Body Prefix - ",
|
||||
"bp-branch-name": "bp_branch_name",
|
||||
"reviewers": "",
|
||||
"assignees": "user3, user4",
|
||||
"no-inherit-reviewers": "true",
|
||||
});
|
||||
|
||||
await runner.execute();
|
||||
|
||||
const cwd = process.cwd() + "/bp";
|
||||
|
||||
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_branch_name");
|
||||
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.fetch).toBeCalledWith(cwd, "merge-requests/2/head:pr/2");
|
||||
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.cherryPick).toBeCalledWith(cwd, "9e15674ebd48e05c6e428a1fa31dbb60a778d644");
|
||||
|
||||
expect(GitCLIService.prototype.push).toBeCalledTimes(1);
|
||||
expect(GitCLIService.prototype.push).toBeCalledWith(cwd, "bp_branch_name");
|
||||
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledTimes(1);
|
||||
expect(GitLabClient.prototype.createPullRequest).toBeCalledWith({
|
||||
owner: "superuser",
|
||||
repo: "backporting-example",
|
||||
head: "bp_branch_name",
|
||||
base: "target",
|
||||
title: "New Title",
|
||||
body: "New Body Prefix - New Body",
|
||||
reviewers: [],
|
||||
assignees: ["user3", "user4"],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
168
test/support/mock/git-client-mock-support.ts
Normal file
168
test/support/mock/git-client-mock-support.ts
Normal file
|
@ -0,0 +1,168 @@
|
|||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { Moctokit } from "@kie/mock-github";
|
||||
import { targetOwner, repo, mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, notFoundPullRequestNumber, sameOwnerPullRequestFixture } from "./github-data";
|
||||
import { CLOSED_NOT_MERGED_MR, MERGED_SQUASHED_MR, OPEN_MR, PROJECT_EXAMPLE, SUPERUSER} from "./gitlab-data";
|
||||
|
||||
const logger = LoggerServiceFactory.getLogger();
|
||||
|
||||
// AXIOS
|
||||
|
||||
export const getAxiosMocked = (url: string) => {
|
||||
let data = undefined;
|
||||
|
||||
// gitlab
|
||||
|
||||
if (url.endsWith("merge_requests/1")) {
|
||||
data = MERGED_SQUASHED_MR;
|
||||
} else if (url.endsWith("merge_requests/2")) {
|
||||
data = OPEN_MR;
|
||||
} else if (url.endsWith("merge_requests/3")) {
|
||||
data = CLOSED_NOT_MERGED_MR;
|
||||
} else if (url.endsWith("projects/76316")) {
|
||||
data = PROJECT_EXAMPLE;
|
||||
} else if (url.endsWith("users?username=superuser")) {
|
||||
data = [SUPERUSER];
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
status: data ? 200 : 404,
|
||||
};
|
||||
};
|
||||
|
||||
export const NEW_GITLAB_MR_ID = 999;
|
||||
export const SECOND_NEW_GITLAB_MR_ID = 1000;
|
||||
export const postAxiosMocked = (_url: string, data?: {source_branch: string,}) => {
|
||||
let responseData = undefined;
|
||||
|
||||
// gitlab
|
||||
|
||||
if (data?.source_branch === "bp-branch") {
|
||||
responseData = {
|
||||
// we do not need the whole response
|
||||
iid: NEW_GITLAB_MR_ID,
|
||||
web_url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + NEW_GITLAB_MR_ID
|
||||
};
|
||||
} if (data?.source_branch === "bp-branch-2") {
|
||||
responseData = {
|
||||
// we do not need the whole response
|
||||
iid: SECOND_NEW_GITLAB_MR_ID,
|
||||
web_url: "https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/" + SECOND_NEW_GITLAB_MR_ID
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
data: responseData,
|
||||
status: responseData ? 200 : 404,
|
||||
};
|
||||
};
|
||||
|
||||
export const putAxiosMocked = (url: string, _data?: unknown) => {
|
||||
const responseData = undefined;
|
||||
|
||||
// gitlab
|
||||
|
||||
if (url.endsWith(`merge_requests/${NEW_GITLAB_MR_ID}`)) {
|
||||
return {
|
||||
data: {
|
||||
iid: NEW_GITLAB_MR_ID,
|
||||
},
|
||||
status: responseData ? 200 : 404,
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error("Error updating merge request: " + url);
|
||||
};
|
||||
|
||||
// GITHUB - OCTOKIT
|
||||
|
||||
export const mockGitHubClient = (apiUrl = "https://api.github.com"): Moctokit => {
|
||||
logger.debug("Setting up moctokit.");
|
||||
|
||||
const mock = new Moctokit(apiUrl);
|
||||
|
||||
// setup the mock requests here
|
||||
|
||||
// valid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: mergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: sameOwnerPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: sameOwnerPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: openPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: openPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notMergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: notMergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.create()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.requestReviewers()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.issues
|
||||
.addAssignees()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: {}
|
||||
});
|
||||
|
||||
|
||||
// invalid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notFoundPullRequestNumber
|
||||
})
|
||||
.reply({
|
||||
status: 404,
|
||||
data: {
|
||||
message: "Not found"
|
||||
}
|
||||
});
|
||||
|
||||
return mock;
|
||||
};
|
|
@ -880,26 +880,7 @@ export const openPullRequestFixture = {
|
|||
"mergeable": null,
|
||||
"rebaseable": null,
|
||||
"mergeable_state": "unknown",
|
||||
"merged_by": {
|
||||
"login": "that-s-a-user",
|
||||
"id": 17157711,
|
||||
"node_id": "MDQ6VXNlcjE3MTU3NzEx",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17157711?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/that-s-a-user",
|
||||
"html_url": "https://github.com/that-s-a-user",
|
||||
"followers_url": "https://api.github.com/users/that-s-a-user/followers",
|
||||
"following_url": "https://api.github.com/users/that-s-a-user/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/that-s-a-user/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/that-s-a-user/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/that-s-a-user/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/that-s-a-user/orgs",
|
||||
"repos_url": "https://api.github.com/users/that-s-a-user/repos",
|
||||
"events_url": "https://api.github.com/users/that-s-a-user/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/that-s-a-user/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"merged_by": {},
|
||||
"comments": 0,
|
||||
"review_comments": 0,
|
||||
"maintainer_can_modify": false,
|
539
test/support/mock/gitlab-data.ts
Normal file
539
test/support/mock/gitlab-data.ts
Normal file
|
@ -0,0 +1,539 @@
|
|||
// <host>/api/v4/projects/superuser%2Fbackporting-example/merge_requests/1
|
||||
// <host>/api/v4/projects/76316
|
||||
|
||||
export const PROJECT_EXAMPLE = {
|
||||
"id":76316,
|
||||
"description":null,
|
||||
"name":"Backporting Example",
|
||||
"name_with_namespace":"Super User / Backporting Example",
|
||||
"path":"backporting-example",
|
||||
"path_with_namespace":"superuser/backporting-example",
|
||||
"created_at":"2023-06-23T13:45:15.121Z",
|
||||
"default_branch":"main",
|
||||
"tag_list":[
|
||||
|
||||
],
|
||||
"topics":[
|
||||
|
||||
],
|
||||
"ssh_url_to_repo":"git@my.gitlab.host.com:superuser/backporting-example.git",
|
||||
"http_url_to_repo":"https://my.gitlab.host.com/superuser/backporting-example.git",
|
||||
"web_url":"https://my.gitlab.host.com/superuser/backporting-example",
|
||||
"readme_url":"https://my.gitlab.host.com/superuser/backporting-example/-/blob/main/README.md",
|
||||
"forks_count":0,
|
||||
"avatar_url":null,
|
||||
"star_count":0,
|
||||
"last_activity_at":"2023-06-28T14:05:42.596Z",
|
||||
"namespace":{
|
||||
"id":70747,
|
||||
"name":"Super User",
|
||||
"path":"superuser",
|
||||
"kind":"user",
|
||||
"full_path":"superuser",
|
||||
"parent_id":null,
|
||||
"avatar_url":"/uploads/-/system/user/avatar/14041/avatar.png",
|
||||
"web_url":"https://my.gitlab.host.com/superuser"
|
||||
},
|
||||
"_links":{
|
||||
"self":"https://my.gitlab.host.com/api/v4/projects/76316",
|
||||
"issues":"https://my.gitlab.host.com/api/v4/projects/76316/issues",
|
||||
"merge_requests":"https://my.gitlab.host.com/api/v4/projects/76316/merge_requests",
|
||||
"repo_branches":"https://my.gitlab.host.com/api/v4/projects/76316/repository/branches",
|
||||
"labels":"https://my.gitlab.host.com/api/v4/projects/76316/labels",
|
||||
"events":"https://my.gitlab.host.com/api/v4/projects/76316/events",
|
||||
"members":"https://my.gitlab.host.com/api/v4/projects/76316/members",
|
||||
"cluster_agents":"https://my.gitlab.host.com/api/v4/projects/76316/cluster_agents"
|
||||
},
|
||||
"packages_enabled":true,
|
||||
"empty_repo":false,
|
||||
"archived":false,
|
||||
"visibility":"private",
|
||||
"owner":{
|
||||
"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"
|
||||
},
|
||||
"resolve_outdated_diff_discussions":false,
|
||||
"container_expiration_policy":{
|
||||
"cadence":"1d",
|
||||
"enabled":false,
|
||||
"keep_n":10,
|
||||
"older_than":"90d",
|
||||
"name_regex":".*",
|
||||
"name_regex_keep":null,
|
||||
"next_run_at":"2023-06-24T13:45:15.167Z"
|
||||
},
|
||||
"issues_enabled":true,
|
||||
"merge_requests_enabled":true,
|
||||
"wiki_enabled":true,
|
||||
"jobs_enabled":true,
|
||||
"snippets_enabled":true,
|
||||
"container_registry_enabled":true,
|
||||
"service_desk_enabled":false,
|
||||
"service_desk_address":null,
|
||||
"can_create_merge_request_in":true,
|
||||
"issues_access_level":"enabled",
|
||||
"repository_access_level":"enabled",
|
||||
"merge_requests_access_level":"enabled",
|
||||
"forking_access_level":"enabled",
|
||||
"wiki_access_level":"enabled",
|
||||
"builds_access_level":"enabled",
|
||||
"snippets_access_level":"enabled",
|
||||
"pages_access_level":"private",
|
||||
"analytics_access_level":"enabled",
|
||||
"container_registry_access_level":"enabled",
|
||||
"security_and_compliance_access_level":"private",
|
||||
"releases_access_level":"enabled",
|
||||
"environments_access_level":"enabled",
|
||||
"feature_flags_access_level":"enabled",
|
||||
"infrastructure_access_level":"enabled",
|
||||
"monitor_access_level":"enabled",
|
||||
"emails_disabled":null,
|
||||
"shared_runners_enabled":true,
|
||||
"lfs_enabled":true,
|
||||
"creator_id":14041,
|
||||
"import_url":null,
|
||||
"import_type":null,
|
||||
"import_status":"none",
|
||||
"import_error":null,
|
||||
"open_issues_count":0,
|
||||
"description_html":"",
|
||||
"updated_at":"2023-06-28T14:05:42.596Z",
|
||||
"ci_default_git_depth":20,
|
||||
"ci_forward_deployment_enabled":true,
|
||||
"ci_job_token_scope_enabled":false,
|
||||
"ci_separated_caches":true,
|
||||
"ci_allow_fork_pipelines_to_run_in_parent_project":true,
|
||||
"build_git_strategy":"fetch",
|
||||
"keep_latest_artifact":true,
|
||||
"restrict_user_defined_variables":false,
|
||||
"runners_token":"GR13489419z7QQ54AUgJaNMFD5asU",
|
||||
"runner_token_expiration_interval":null,
|
||||
"group_runners_enabled":true,
|
||||
"auto_cancel_pending_pipelines":"enabled",
|
||||
"build_timeout":3600,
|
||||
"auto_devops_enabled":false,
|
||||
"auto_devops_deploy_strategy":"continuous",
|
||||
"ci_config_path":"",
|
||||
"public_jobs":true,
|
||||
"shared_with_groups":[
|
||||
|
||||
],
|
||||
"only_allow_merge_if_pipeline_succeeds":false,
|
||||
"allow_merge_on_skipped_pipeline":null,
|
||||
"request_access_enabled":true,
|
||||
"only_allow_merge_if_all_discussions_are_resolved":false,
|
||||
"remove_source_branch_after_merge":true,
|
||||
"printing_merge_request_link_enabled":true,
|
||||
"merge_method":"merge",
|
||||
"squash_option":"default_off",
|
||||
"enforce_auth_checks_on_uploads":true,
|
||||
"suggestion_commit_message":null,
|
||||
"merge_commit_template":null,
|
||||
"squash_commit_template":null,
|
||||
"issue_branch_template":null,
|
||||
"autoclose_referenced_issues":true,
|
||||
"approvals_before_merge":0,
|
||||
"mirror":false,
|
||||
"external_authorization_classification_label":null,
|
||||
"marked_for_deletion_at":null,
|
||||
"marked_for_deletion_on":null,
|
||||
"requirements_enabled":false,
|
||||
"requirements_access_level":"enabled",
|
||||
"security_and_compliance_enabled":true,
|
||||
"compliance_frameworks":[
|
||||
|
||||
],
|
||||
"issues_template":null,
|
||||
"merge_requests_template":null,
|
||||
"merge_pipelines_enabled":false,
|
||||
"merge_trains_enabled":false,
|
||||
"allow_pipeline_trigger_approve_deployment":false,
|
||||
"permissions":{
|
||||
"project_access":{
|
||||
"access_level":50,
|
||||
"notification_level":3
|
||||
},
|
||||
"group_access":null
|
||||
}
|
||||
};
|
||||
|
||||
export const MERGED_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":[
|
||||
|
||||
],
|
||||
"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":"ebb1eca696c42fd067658bd9b5267709f78ef38e",
|
||||
"discussion_locked":null,
|
||||
"should_remove_source_branch":true,
|
||||
"force_remove_source_branch":true,
|
||||
"reference":"!2",
|
||||
"references":{
|
||||
"short":"!2",
|
||||
"relative":"!2",
|
||||
"full":"superuser/backporting-example!2"
|
||||
},
|
||||
"web_url":"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/1",
|
||||
"time_stats":{
|
||||
"time_estimate":0,
|
||||
"total_time_spent":0,
|
||||
"human_time_estimate":null,
|
||||
"human_total_time_spent":null
|
||||
},
|
||||
"squash":true,
|
||||
"squash_on_merge":true,
|
||||
"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
|
||||
}
|
||||
};
|
||||
|
||||
export const OPEN_MR = {
|
||||
"id":807106,
|
||||
"iid":2,
|
||||
"project_id":76316,
|
||||
"title":"Update test.txt opened",
|
||||
"description":"Still opened mr body",
|
||||
"state":"opened",
|
||||
"created_at":"2023-06-28T14:32:40.943Z",
|
||||
"updated_at":"2023-06-28T14:35:56.433Z",
|
||||
"merged_by":null,
|
||||
"merge_user":null,
|
||||
"merged_at":null,
|
||||
"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":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"
|
||||
}
|
||||
],
|
||||
"source_project_id":76316,
|
||||
"target_project_id":76316,
|
||||
"labels":[
|
||||
|
||||
],
|
||||
"draft":false,
|
||||
"work_in_progress":false,
|
||||
"milestone":null,
|
||||
"merge_when_pipeline_succeeds":false,
|
||||
"merge_status":"checking",
|
||||
"detailed_merge_status":"checking",
|
||||
"sha":"9e15674ebd48e05c6e428a1fa31dbb60a778d644",
|
||||
"merge_commit_sha":null,
|
||||
"squash_commit_sha":null,
|
||||
"discussion_locked":null,
|
||||
"should_remove_source_branch":null,
|
||||
"force_remove_source_branch":true,
|
||||
"reference":"!2",
|
||||
"references":{
|
||||
"short":"!2",
|
||||
"relative":"!2",
|
||||
"full":"superuser/backporting-example!2"
|
||||
},
|
||||
"web_url":"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/2",
|
||||
"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
|
||||
}
|
||||
};
|
||||
|
||||
export const CLOSED_NOT_MERGED_MR = {
|
||||
"id":807191,
|
||||
"iid":3,
|
||||
"project_id":76316,
|
||||
"title":"Update test.txt",
|
||||
"description":"",
|
||||
"state":"closed",
|
||||
"created_at":"2023-06-28T15:44:50.549Z",
|
||||
"updated_at":"2023-06-28T15:44:58.318Z",
|
||||
"merged_by":null,
|
||||
"merge_user":null,
|
||||
"merged_at":null,
|
||||
"closed_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"
|
||||
},
|
||||
"closed_at":"2023-06-28T15:44:58.349Z",
|
||||
"target_branch":"main",
|
||||
"source_branch":"closed",
|
||||
"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":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"
|
||||
}
|
||||
],
|
||||
"source_project_id":76316,
|
||||
"target_project_id":76316,
|
||||
"labels":[
|
||||
|
||||
],
|
||||
"draft":false,
|
||||
"work_in_progress":false,
|
||||
"milestone":null,
|
||||
"merge_when_pipeline_succeeds":false,
|
||||
"merge_status":"can_be_merged",
|
||||
"detailed_merge_status":"not_open",
|
||||
"sha":"c8ce0ffdd372c2ed89d65f9e3f6f3681e6d16eb3",
|
||||
"merge_commit_sha":null,
|
||||
"squash_commit_sha":null,
|
||||
"discussion_locked":null,
|
||||
"should_remove_source_branch":null,
|
||||
"force_remove_source_branch":true,
|
||||
"reference":"!3",
|
||||
"references":{
|
||||
"short":"!3",
|
||||
"relative":"!3",
|
||||
"full":"superuser/backporting-example!3"
|
||||
},
|
||||
"web_url":"https://my.gitlab.host.com/superuser/backporting-example/-/merge_requests/3",
|
||||
"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":"4d369c3e9a8d1d5b7e56c892a8ab2a7666583ac3",
|
||||
"head_sha":"c8ce0ffdd372c2ed89d65f9e3f6f3681e6d16eb3",
|
||||
"start_sha":"4d369c3e9a8d1d5b7e56c892a8ab2a7666583ac3"
|
||||
},
|
||||
"merge_error":null,
|
||||
"first_contribution":false,
|
||||
"user":{
|
||||
"can_merge":true
|
||||
}
|
||||
};
|
||||
|
||||
export const SUPERUSER = {
|
||||
"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"
|
||||
};
|
|
@ -1,89 +0,0 @@
|
|||
import LoggerServiceFactory from "@bp/service/logger/logger-service-factory";
|
||||
import { Moctokit } from "@kie/mock-github";
|
||||
import { targetOwner, repo, mergedPullRequestFixture, openPullRequestFixture, notMergedPullRequestFixture, notFoundPullRequestNumber, sameOwnerPullRequestFixture } from "./moctokit-data";
|
||||
|
||||
const logger = LoggerServiceFactory.getLogger();
|
||||
|
||||
export const setupMoctokit = (): Moctokit => {
|
||||
logger.debug("Setting up moctokit.");
|
||||
|
||||
const mock = new Moctokit();
|
||||
|
||||
// setup the mock requests here
|
||||
|
||||
// valid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: mergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: sameOwnerPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: sameOwnerPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: openPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: openPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notMergedPullRequestFixture.number
|
||||
})
|
||||
.reply({
|
||||
status: 200,
|
||||
data: notMergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.create()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
mock.rest.pulls
|
||||
.requestReviewers()
|
||||
.reply({
|
||||
status: 201,
|
||||
data: mergedPullRequestFixture
|
||||
});
|
||||
|
||||
|
||||
// invalid requests
|
||||
mock.rest.pulls
|
||||
.get({
|
||||
owner: targetOwner,
|
||||
repo: repo,
|
||||
pull_number: notFoundPullRequestNumber
|
||||
})
|
||||
.reply({
|
||||
status: 404,
|
||||
data: {
|
||||
message: "Not found"
|
||||
}
|
||||
});
|
||||
|
||||
return mock;
|
||||
};
|
Loading…
Add table
Reference in a new issue