package io.jpom.util; import cn.hutool.core.date.DateTime; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import io.jpom.system.ConfigBean; import io.jpom.system.JpomRuntimeException; import org.eclipse.jgit.api.CreateBranchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.RemoteListCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * git工具 * * @author bwcx_jzy * @date 2019/7/15 **/ public class GitUtil { /** * 检查本地的remote是否存在对应的url * * @param url 要检查的url * @param file 本地仓库文件 * @return true 存在对应url * @throws IOException IO * @throws GitAPIException E */ private static boolean checkRemoteUrl(String url, File file) throws IOException, GitAPIException { try (Git git = Git.open(file)) { RemoteListCommand remoteListCommand = git.remoteList(); boolean urlTrue = false; List<RemoteConfig> list = remoteListCommand.call(); end: for (RemoteConfig remoteConfig : list) { for (URIish urIish : remoteConfig.getURIs()) { if (urIish.toString().equals(url)) { urlTrue = true; break end; } } } return urlTrue; } } /** * 删除重新clone * * @param url url * @param file 文件 * @param credentialsProvider 凭证 * @return git * @throws GitAPIException api * @throws IOException 删除文件失败 */ private static Git reClone(String url, File file, CredentialsProvider credentialsProvider) throws GitAPIException, IOException { if (!FileUtil.clean(file)) { throw new IOException("del error:" + file.getPath()); } return Git.cloneRepository() .setURI(url) .setDirectory(file) .setCredentialsProvider(credentialsProvider) .call(); } private static Git initGit(String url, File file, CredentialsProvider credentialsProvider) throws IOException, GitAPIException { Git git; if (FileUtil.file(file, Constants.DOT_GIT).exists()) { if (checkRemoteUrl(url, file)) { git = Git.open(file); // git.pull().setCredentialsProvider(credentialsProvider).call(); } else { git = reClone(url, file, credentialsProvider); } } else { git = reClone(url, file, credentialsProvider); } return git; } /** * 获取仓库远程的所有分支 * * @param url 远程url * @param file 仓库clone到本地的文件夹 * @param credentialsProvider 凭证 * @return list * @throws GitAPIException api * @throws IOException IO */ private static List<String> branchList(String url, File file, CredentialsProvider credentialsProvider) throws GitAPIException, IOException { try (Git git = initGit(url, file, credentialsProvider)) { // List<Ref> list = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); List<String> all = new ArrayList<>(list.size()); list.forEach(ref -> { String name = ref.getName(); if (name.startsWith(Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME)) { all.add(name.substring((Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME).length() + 1)); } }); return all; } catch (TransportException t) { checkTransportException(t); throw t; } } public static List<String> getBranchList(String url, String userName, String userPwd) throws GitAPIException, IOException { // 生成临时路径 String tempId = SecureUtil.md5(url); File file = ConfigBean.getInstance().getTempPath(); File gitFile = FileUtil.file(file, "gitTemp", tempId); List<String> list = branchList(url, gitFile, new UsernamePasswordCredentialsProvider(userName, userPwd)); if (list.isEmpty()) { throw new JpomRuntimeException("该仓库还没有任何分支"); } return list; } /** * 拉取对应分支最新代码 * * @param url 远程url * @param file 仓库路径 * @param branchName 分支名 * @param credentialsProvider 凭证 * @throws IOException IO * @throws GitAPIException api */ public static void checkoutPull(String url, File file, String branchName, CredentialsProvider credentialsProvider) throws IOException, GitAPIException { try (Git git = initGit(url, file, credentialsProvider)) { // 判断本地是否存在对应分支 List<Ref> list = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); boolean createBranch = true; for (Ref ref : list) { String name = ref.getName(); if (name.startsWith(Constants.R_HEADS + branchName)) { createBranch = false; break; } } // 切换分支 if (!StrUtil.equals(git.getRepository().getBranch(), branchName)) { git.checkout(). setCreateBranch(createBranch). setName(branchName). setForceRefUpdate(true). setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM). call(); } git.pull().setCredentialsProvider(credentialsProvider).call(); } catch (TransportException t) { checkTransportException(t); throw t; } } private static void checkTransportException(TransportException ex) { String msg = ex.getMessage(); if (msg.contains(JGitText.get().notAuthorized) || msg.contains(JGitText.get().authenticationNotSupported)) { throw new JpomRuntimeException("git账号密码不正常", ex); } } private static AnyObjectId getAnyObjectId(Git git, String branchName) throws GitAPIException { List<Ref> list = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); for (Ref ref : list) { String name = ref.getName(); if (name.startsWith(Constants.R_HEADS + branchName)) { return ref.getObjectId(); } } return null; } /** * 获取对应分支的最后一次提交记录 * * @param file 仓库文件夹 * @param branchName 分支 * @return 描述 * @throws IOException IO * @throws GitAPIException api */ public static String getLastCommitMsg(File file, String branchName) throws IOException, GitAPIException { try (Git git = Git.open(file)) { AnyObjectId anyObjectId = getAnyObjectId(git, branchName); Objects.requireNonNull(anyObjectId, "没有" + branchName + "分支"); RevWalk walk = new RevWalk(git.getRepository()); RevCommit revCommit = walk.parseCommit(anyObjectId); String time = new DateTime(revCommit.getCommitTime() * 1000L).toString(); PersonIdent personIdent = revCommit.getAuthorIdent(); return StrUtil.format("{} {} {}[{}] {}", branchName, revCommit.getShortMessage(), personIdent.getName(), personIdent.getEmailAddress(), time); } } }