1
0
Fork 0
mirror of https://code.forgejo.org/actions/git-backporting synced 2025-03-14 22:27:02 +01:00

feat: integrate with codeberg (#80)

This commit is contained in:
Andrea Lamparelli 2023-08-18 13:15:38 +02:00 committed by GitHub
parent eecbff34b7
commit 9f0fbc0b2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 72 additions and 25 deletions

View file

@ -31,7 +31,7 @@ Table of content
## Who is this tool for?
`git-backporting` is a tool that provides capabilities to *backport* pull requests (on *GitHub*) and merge requests (on *GitLab*) in an automated way.
`git-backporting` is a fully configurable tool that provides capabilities to *backport* pull requests (on *GitHub*) and merge requests (on *GitLab*) in an automated way.
> *What is backporting?* - 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.
@ -139,6 +139,8 @@ Right now **Git Backporting** supports the following git management services:
* ***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.
* ***CODEBERG***: Introduced since version `4.4.0`, it works for public [codeberg.org](https://codeberg.org/) platform. Thanks to the api compatibility with GitHub, the interaction with this service is performed using using [*octokit*](https://octokit.github.io/rest.js) client library.
> **NOTE**: by default, all gitlab requests are performed setting `rejectUnauthorized=false`, planning to make this configurable too.
## GitHub action

22
dist/cli/index.js vendored
View file

@ -566,6 +566,9 @@ class GitClientFactory {
case git_types_1.GitClientType.GITLAB:
GitClientFactory.instance = new gitlab_client_1.default(authToken, apiUrl);
break;
case git_types_1.GitClientType.CODEBERG:
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl);
break;
default:
throw new Error(`Invalid git service type received: ${type}`);
}
@ -607,6 +610,9 @@ const inferGitClient = (prUrl) => {
else if (stdPrUrl.includes(git_types_1.GitClientType.GITLAB.toString())) {
return git_types_1.GitClientType.GITLAB;
}
else if (stdPrUrl.includes(git_types_1.GitClientType.CODEBERG.toString())) {
return git_types_1.GitClientType.CODEBERG;
}
throw new Error(`Remote git service not recognized from pr url: ${prUrl}`);
};
exports.inferGitClient = inferGitClient;
@ -640,6 +646,7 @@ var GitClientType;
(function (GitClientType) {
GitClientType["GITHUB"] = "github";
GitClientType["GITLAB"] = "gitlab";
GitClientType["CODEBERG"] = "codeberg";
})(GitClientType = exports.GitClientType || (exports.GitClientType = {}));
var GitRepoState;
(function (GitRepoState) {
@ -661,6 +668,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const git_types_1 = __nccwpck_require__(750);
const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
@ -673,7 +681,7 @@ class GitHubClient {
}
// READ
getDefaultGitUser() {
return "GitHub";
return this.apiUrl.includes(git_types_1.GitClientType.CODEBERG.toString()) ? "Codeberg" : "GitHub";
}
getDefaultGitEmail() {
return "noreply@github.com";
@ -806,9 +814,9 @@ class GitHubMapper {
state: this.mapGitState(pr.state),
merged: pr.merged ?? false,
mergedBy: pr.merged_by?.login,
reviewers: pr.requested_reviewers.filter(r => "login" in r).map((r => r?.login)),
assignees: pr.assignees.filter(r => "login" in r).map(r => r.login),
labels: pr.labels.map(l => l.name),
reviewers: pr.requested_reviewers?.filter(r => "login" in r).map((r => r?.login)) ?? [],
assignees: pr.assignees?.filter(r => "login" in r).map(r => r.login) ?? [],
labels: pr.labels?.map(l => l.name) ?? [],
sourceRepo: await this.mapSourceRepo(pr),
targetRepo: await this.mapTargetRepo(pr),
nCommits: pr.commits,
@ -1260,8 +1268,8 @@ class Runner {
}
// 2. init git service
const gitClientType = (0, git_util_1.inferGitClient)(args.pullRequest);
// right now the apiVersion is set to v4
const apiUrl = (0, git_util_1.inferGitApiUrl)(args.pullRequest);
// the api version is ignored in case of github
const apiUrl = (0, git_util_1.inferGitApiUrl)(args.pullRequest, gitClientType === git_types_1.GitClientType.CODEBERG ? "v1" : undefined);
const gitApi = git_client_factory_1.default.getOrCreate(gitClientType, args.auth, apiUrl);
// 3. parse configs
this.logger.debug("Parsing configs..");
@ -1302,7 +1310,7 @@ class Runner {
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
configs.originalPullRequest.state === "open") {
this.logger.debug("Fetching pull request remote..");
const prefix = git.gitClientType === git_types_1.GitClientType.GITHUB ? "pull" : "merge-requests"; // default is for gitlab
const prefix = git.gitClientType === git_types_1.GitClientType.GITLAB ? "merge-requests" : "pull"; // default is for gitlab
await git.gitCli.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
}
// 7. apply all changes to the new branch

22
dist/gha/index.js vendored
View file

@ -536,6 +536,9 @@ class GitClientFactory {
case git_types_1.GitClientType.GITLAB:
GitClientFactory.instance = new gitlab_client_1.default(authToken, apiUrl);
break;
case git_types_1.GitClientType.CODEBERG:
GitClientFactory.instance = new github_client_1.default(authToken, apiUrl);
break;
default:
throw new Error(`Invalid git service type received: ${type}`);
}
@ -577,6 +580,9 @@ const inferGitClient = (prUrl) => {
else if (stdPrUrl.includes(git_types_1.GitClientType.GITLAB.toString())) {
return git_types_1.GitClientType.GITLAB;
}
else if (stdPrUrl.includes(git_types_1.GitClientType.CODEBERG.toString())) {
return git_types_1.GitClientType.CODEBERG;
}
throw new Error(`Remote git service not recognized from pr url: ${prUrl}`);
};
exports.inferGitClient = inferGitClient;
@ -610,6 +616,7 @@ var GitClientType;
(function (GitClientType) {
GitClientType["GITHUB"] = "github";
GitClientType["GITLAB"] = "gitlab";
GitClientType["CODEBERG"] = "codeberg";
})(GitClientType = exports.GitClientType || (exports.GitClientType = {}));
var GitRepoState;
(function (GitRepoState) {
@ -631,6 +638,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const git_types_1 = __nccwpck_require__(750);
const github_mapper_1 = __importDefault(__nccwpck_require__(5764));
const octokit_factory_1 = __importDefault(__nccwpck_require__(4257));
const logger_service_factory_1 = __importDefault(__nccwpck_require__(8936));
@ -643,7 +651,7 @@ class GitHubClient {
}
// READ
getDefaultGitUser() {
return "GitHub";
return this.apiUrl.includes(git_types_1.GitClientType.CODEBERG.toString()) ? "Codeberg" : "GitHub";
}
getDefaultGitEmail() {
return "noreply@github.com";
@ -776,9 +784,9 @@ class GitHubMapper {
state: this.mapGitState(pr.state),
merged: pr.merged ?? false,
mergedBy: pr.merged_by?.login,
reviewers: pr.requested_reviewers.filter(r => "login" in r).map((r => r?.login)),
assignees: pr.assignees.filter(r => "login" in r).map(r => r.login),
labels: pr.labels.map(l => l.name),
reviewers: pr.requested_reviewers?.filter(r => "login" in r).map((r => r?.login)) ?? [],
assignees: pr.assignees?.filter(r => "login" in r).map(r => r.login) ?? [],
labels: pr.labels?.map(l => l.name) ?? [],
sourceRepo: await this.mapSourceRepo(pr),
targetRepo: await this.mapTargetRepo(pr),
nCommits: pr.commits,
@ -1230,8 +1238,8 @@ class Runner {
}
// 2. init git service
const gitClientType = (0, git_util_1.inferGitClient)(args.pullRequest);
// right now the apiVersion is set to v4
const apiUrl = (0, git_util_1.inferGitApiUrl)(args.pullRequest);
// the api version is ignored in case of github
const apiUrl = (0, git_util_1.inferGitApiUrl)(args.pullRequest, gitClientType === git_types_1.GitClientType.CODEBERG ? "v1" : undefined);
const gitApi = git_client_factory_1.default.getOrCreate(gitClientType, args.auth, apiUrl);
// 3. parse configs
this.logger.debug("Parsing configs..");
@ -1272,7 +1280,7 @@ class Runner {
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
configs.originalPullRequest.state === "open") {
this.logger.debug("Fetching pull request remote..");
const prefix = git.gitClientType === git_types_1.GitClientType.GITHUB ? "pull" : "merge-requests"; // default is for gitlab
const prefix = git.gitClientType === git_types_1.GitClientType.GITLAB ? "merge-requests" : "pull"; // default is for gitlab
await git.gitCli.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
}
// 7. apply all changes to the new branch

View file

@ -43,6 +43,9 @@ export default class GitClientFactory {
case GitClientType.GITLAB:
GitClientFactory.instance = new GitLabClient(authToken, apiUrl);
break;
case GitClientType.CODEBERG:
GitClientFactory.instance = new GitHubService(authToken, apiUrl);
break;
default:
throw new Error(`Invalid git service type received: ${type}`);
}

View file

@ -16,6 +16,8 @@ export const inferGitClient = (prUrl: string): GitClientType => {
return GitClientType.GITHUB;
} else if (stdPrUrl.includes(GitClientType.GITLAB.toString())) {
return GitClientType.GITLAB;
} else if (stdPrUrl.includes(GitClientType.CODEBERG.toString())) {
return GitClientType.CODEBERG;
}
throw new Error(`Remote git service not recognized from pr url: ${prUrl}`);

View file

@ -41,6 +41,7 @@ export interface BackportPullRequest {
export enum GitClientType {
GITHUB = "github",
GITLAB = "gitlab",
CODEBERG = "codeberg",
}
export enum GitRepoState {

View file

@ -1,5 +1,5 @@
import GitClient from "@bp/service/git/git-client";
import { BackportPullRequest, GitPullRequest } from "@bp/service/git/git.types";
import { BackportPullRequest, GitClientType, GitPullRequest } from "@bp/service/git/git.types";
import GitHubMapper from "@bp/service/git/github/github-mapper";
import OctokitFactory from "@bp/service/git/github/octokit-factory";
import LoggerService from "@bp/service/logger/logger-service";
@ -24,7 +24,7 @@ export default class GitHubClient implements GitClient {
// READ
getDefaultGitUser(): string {
return "GitHub";
return this.apiUrl.includes(GitClientType.CODEBERG.toString()) ? "Codeberg" : "GitHub";
}
getDefaultGitEmail(): string {

View file

@ -24,9 +24,9 @@ export default class GitHubMapper implements GitResponseMapper<PullRequest, "ope
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),
labels: pr.labels.map(l => l.name),
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) ?? [],
labels: pr.labels?.map(l => l.name) ?? [],
sourceRepo: await this.mapSourceRepo(pr),
targetRepo: await this.mapTargetRepo(pr),
nCommits: pr.commits,

View file

@ -61,8 +61,8 @@ export default class Runner {
// 2. init git service
const gitClientType: GitClientType = inferGitClient(args.pullRequest);
// right now the apiVersion is set to v4
const apiUrl = inferGitApiUrl(args.pullRequest);
// the api version is ignored in case of github
const apiUrl = inferGitApiUrl(args.pullRequest, gitClientType === GitClientType.CODEBERG ? "v1" : undefined);
const gitApi: GitClient = GitClientFactory.getOrCreate(gitClientType, args.auth, apiUrl);
// 3. parse configs
@ -112,7 +112,7 @@ export default class Runner {
if (configs.originalPullRequest.sourceRepo.owner !== configs.originalPullRequest.targetRepo.owner ||
configs.originalPullRequest.state === "open") {
this.logger.debug("Fetching pull request remote..");
const prefix = git.gitClientType === GitClientType.GITHUB ? "pull" : "merge-requests"; // default is for gitlab
const prefix = git.gitClientType === GitClientType.GITLAB ? "merge-requests" : "pull" ; // default is for gitlab
await git.gitCli.fetch(configs.folder, `${prefix}/${configs.originalPullRequest.number}/head:pr/${configs.originalPullRequest.number}`);
}

View file

@ -20,6 +20,11 @@ describe("git client factory test", () => {
expect(client).toBeInstanceOf(GitLabClient);
});
test("correctly create codeberg client", () => {
const client = GitClientFactory.getOrCreate(GitClientType.CODEBERG, "auth", "apiurl");
expect(client).toBeInstanceOf(GitHubClient);
});
test("check get service github", () => {
const create = GitClientFactory.getOrCreate(GitClientType.GITHUB, "auth", "apiurl");
const get = GitClientFactory.getClient();
@ -31,4 +36,10 @@ describe("git client factory test", () => {
const get = GitClientFactory.getClient();
expect(create).toStrictEqual(get);
});
test("check get service codeberg", () => {
const create = GitClientFactory.getOrCreate(GitClientType.CODEBERG, "auth", "apiurl");
const get = GitClientFactory.getClient();
expect(create).toStrictEqual(get);
});
});

View file

@ -23,6 +23,18 @@ describe("check git utilities", () => {
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 api from github api url", ()=> {
expect(inferGitApiUrl("https://api.github.com/repos/owner/repo/pulls/1")).toStrictEqual("https://api.github.com");
});
test("check infer codeberg api", ()=> {
expect(inferGitApiUrl("https://codeberg.org/lampajr/backporting-example/pulls/1", "v1")).toStrictEqual("https://codeberg.org/api/v1");
});
test("check infer codeberg api", ()=> {
expect(inferGitApiUrl("https://codeberg.org/lampajr/backporting-example/pulls/1", undefined)).toStrictEqual("https://codeberg.org/api/v4");
});
test("check infer github client", ()=> {
expect(inferGitClient("https://github.com/superuser/backporting-example/pull/4")).toStrictEqual(GitClientType.GITHUB);
});
@ -39,7 +51,7 @@ describe("check git utilities", () => {
expect(inferGitClient("https://api.github.com/repos/owner/repo/pulls/1")).toStrictEqual(GitClientType.GITHUB);
});
test("check infer github api from github api url", ()=> {
expect(inferGitApiUrl("https://api.github.com/repos/owner/repo/pulls/1")).toStrictEqual("https://api.github.com");
test("check infer codeberg client", ()=> {
expect(inferGitClient("https://codeberg.org/lampajr/backporting-example/pulls/1")).toStrictEqual(GitClientType.CODEBERG);
});
});