一、背景介绍
现在有两个代码仓库 gitee、gitlab,之前主要用的gitee、现在要将代码同步到gitlab上面,目前使用的是gitee的webhook功能,推送时会调用接口
二、导入包
pom文件中先导入jgit的包 具体的版本号可以根据自己的springboot版本去导入
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>6.4.0.202211300538-r</version>
</dependency>
// 下面是一些工具的包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
三、具体代码实现
1.主方法,写得比较急,没有整理,后续会慢慢整理
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
上面是导入的包
// gitee仓库地址,不带仓库名的地址,如实际地址为https://gitee.com/aaa/bbb.git,去掉最后的bbb.git
private final String remoteAddress = "https://gitee.com/aaa/";
// gitlab仓库地址与上面相同,都是不带xxx.git
private final String GITLAB_URL = "https://xxx.xxx.com/xxx/";
// gitee登录账号
private final String GITEE_USERNAME = "xxx";
// gitee登录密码
private final String GITEE_PASSWORD = "password";
// gitlab登录账号
private final String GITLAB_USERNAME = "xxx";
// gitlab登录密码
private final String GITLAB_PASSWORD = "password";
@PostMapping("/gitee-webhook")
public void handleWebHook(@RequestBody JSONObject jsonObject) {
System.out.println("params = " + jsonObject);
/*
获取gitee的webhook参数中的文件名称、用户名、以及分支(看了一下webhook返回的参数,
只有这个字段中存在分支名称,就取了这个字段的信息,可以结合实际自己取)
*/
String projectName = jsonObject.getString("projectName");
String userName = jsonObject.getString("user_name");
String ref = jsonObject.getString("ref");
String branch = ref.substring(ref.lastIndexOf("/") + 1, ref.length());
System.out.println("projectName = " + projectName);
System.out.println("userName = " + userName);
System.out.println("branch = " + branch);
// 获取提交的信息,用于推送到gitlab上时传的message(这个也可以自己直接填固定的)
JSONArray commits = jsonObject.getJSONArray("commits");
String messageStr = "auto commit";
if (null != commits) {
List<String> messages = new ArrayList<>();
for (int i = 0; i < commits.size(); i++) {
JSONObject commit = commits.getJSONObject(i);
String message = commit.getString("message");
if (message.contains("\n")) {
message = message.substring(0, message.indexOf("\n"));
}
messages.add(message);
}
messageStr = StrUtil.join(",", messages.iterator());
}
System.out.println(messageStr);
// 获取当前程序所在的文件夹路径
String property = System.getProperty("user.dir");
property = property.replaceAll("/", "\\");
property = property.substring(0, property.lastIndexOf("\\") + 1);
try {
// 删除旧的gitlab和gitee本地文件
FileUtils.deleteDirectory(new File(property + projectName));
FileUtils.deleteDirectory(new File(property + projectName + "gitee"));
File giteeRepository = new File(property + projectName + "gitee");
File gitlabRepository = new File(property + projectName);
// 克隆GitLab仓库到本地
Git git = Git.cloneRepository()
.setURI(GITLAB_URL + projectName + ".git")
.setDirectory(gitlabRepository)
.setBranch(branch)
.setCredentialsProvider(getGitlabCredentialsProvider())
.call();
// 克隆Gitee仓库到本地
Git gitee = Git.cloneRepository()
.setURI(remoteAddress + projectName + ".git")
.setBranch(branch)
.setDirectory(giteeRepository)
.setCredentialsProvider(getGiteeCredentialsProvider())
.call();
// 检测Gitee上删除的文件
List<String> deletedFiles = detectDeletedFiles(giteeRepository, gitlabRepository);
// 删除本地gitlab项目文件下的所有文件(.git文件不能删除)
delGitlabFiles(gitlabRepository);
// 复制从Gitee仓库获取的代码到GitLab仓库
copyCodeFiles(giteeRepository, gitlabRepository);
// 删除远程GitLab仓库上被删除的文件
deleteFilesInGitLab(deletedFiles, git);
// 判断是当前分支是哪个分支
if (branchNameExist(git, branch)) {
System.out.println("本地存在该分支");
git.checkout().setCreateBranch(false).setName(branch).call();
} else {
System.out.println("本地不存在该分支");
git.checkout().setCreateBranch(true).setName(branch).setStartPoint("origin/" + branch).call();
}
// 提交并推送到GitLab
git.add().addFilepattern(".").call();
git.commit().setMessage(messageStr).call();
git.push().setCredentialsProvider(getGitlabCredentialsProvider()).call();
// 最后关闭资源
gitee.close();
git.close();
} catch (IOException | GitAPIException e) {
e.printStackTrace();
}
}
2.工具方法,上文中可能用到(有些是chatgpt生成的,可能有些许小问题,但是没什么大的问题,自己已经测试过了)
public boolean branchNameExist(Git git, String branchName) throws IOException {
Repository repository = git.getRepository();
Ref ref = repository.findRef(branchName);
return ref != null;
/*List refs = git.branchList().call();
for (Ref ref : refs) {
if (ref.getName().contains(branchName)) {
return true;
}
}*/
}
private void delGitlabFiles(File gitlabFlie) {
List<File> files = (List<File>) FileUtils.listFiles(gitlabFlie, null, false);
for (File file : files) {
if (".git".equals(file.getName())) {
continue;
}
file.deleteOnExit();
}
}
private static List<String> detectDeletedFiles(File giteeRepoDir, File gitlabRepoDir) {
List<String> deletedFiles = new ArrayList<>();
List<File> gitlabFiles = (List<File>) FileUtils.listFiles(gitlabRepoDir, null, true);
for (File gitlabFile : gitlabFiles) {
if (gitlabFile.getAbsolutePath().contains(".git")) {
continue;
}
String relativePath = gitlabFile.getAbsolutePath().replace(gitlabRepoDir.getAbsolutePath(), "");
File correspondingFile = new File(giteeRepoDir, relativePath);
if (!correspondingFile.exists()) {
deletedFiles.add(relativePath.replaceAll("\\\\", ""));
}
}
return deletedFiles;
}
private void deleteFilesInGitLab(List<String> deletedFiles, Git git) throws GitAPIException {
for (String deletedFile : deletedFiles) {
git.rm().addFilepattern(deletedFile).call();
}
}
private static void copyCodeFiles(File sourceDir, File targetDir) throws IOException {
// 获取Gitee仓库的文件列表
File[] sourceFiles = sourceDir.listFiles();
if (sourceFiles != null) {
// 遍历文件并复制到GitLab仓库
for (File sourceFile : sourceFiles) {
if (".git".equals(sourceFile.getName())) {
continue;
}
if (sourceFile.isFile()) {
// 排除复制.git文件夹
File targetFile = new File(targetDir, sourceFile.getName());
FileUtils.copyFile(sourceFile, targetFile);
} else if (sourceFile.isDirectory()) {
// 递归复制子文件夹
File targetSubDir = new File(targetDir, sourceFile.getName());
copyCodeFiles(sourceFile, targetSubDir);
}
}
}
}
private CredentialsProvider getGiteeCredentialsProvider() {
return new UsernamePasswordCredentialsProvider(GITEE_USERNAME, GITEE_PASSWORD);
}
private CredentialsProvider getGitlabCredentialsProvider() {
return new UsernamePasswordCredentialsProvider(GITLAB_USERNAME, GITLAB_PASSWORD);
}
三、在gitee中配置webhook,地址就为当前接口的地址
四、测试
可在gitee中创建一个文件夹,并填入值,会自动同步webhook地址,然后检查一下gitlab上是否有变动