使用JGIT自动同步gitee代码到gitlab

一、背景介绍

现在有两个代码仓库 gitee、gitlab,之前主要用的gitee、现在要将代码同步到gitlab上面,目前使用的是gitee的webhook功能,推送时会调用接口

前提:gitee中的仓库和gitlab仓库要一致,分支要先手动创建好

二、导入包

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上是否有变动

你可能感兴趣的:(git,gitee,gitlab)