From f69e5f7a4f430470af3040724fb110cae746b968 Mon Sep 17 00:00:00 2001 From: liuxiaohua Date: Fri, 13 Jun 2025 16:49:05 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20[2025-06-13]=20=E6=B7=BB=E5=8A=A0Ja?= =?UTF-8?q?va=E4=BD=BF=E7=94=A8Maven=E5=8F=8AGitlab=E6=95=99=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../技术实现/20250613-Java使用Maven及Gitlab.md | 444 ++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 文档/技术实现/20250613-Java使用Maven及Gitlab.md diff --git a/文档/技术实现/20250613-Java使用Maven及Gitlab.md b/文档/技术实现/20250613-Java使用Maven及Gitlab.md new file mode 100644 index 0000000..10cb9c3 --- /dev/null +++ b/文档/技术实现/20250613-Java使用Maven及Gitlab.md @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + +# Java使用Maven及Gitlab + +## Java使用Maven +### 所需依赖 +```xml + + + + + org.apache.maven + maven-embedder + 3.9.6 + + + + org.apache.maven + maven-compat + 3.9.6 + + + + org.apache.maven.resolver + maven-resolver-transport-http + 1.9.18 + + + org.apache.maven.resolver + maven-resolver-connector-basic + 1.9.18 + + + + org.apache.maven + maven-resolver-provider + 3.9.6 + + + + org.apache.maven + maven-settings-builder + 3.9.6 + + +``` +### 使用Archetype生成项目 +```java +package org.jeecg.modules.devops.archetype; + +import lombok.extern.slf4j.Slf4j; +import org.apache.maven.cli.MavenCli; +import org.jeecg.modules.devops.model.YuanMengOnlineService; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +@Slf4j +public class MavenUtils { + + private static final String ARCHETYPE_GROUP_ID = "com.yuanmeng.engine"; + private static final String ARCHETYPE_ARTIFACT_ID = "engine-archetype-web"; + private static final String ARCHETYPE_VERSION = "2.0.2-SNAPSHOT"; + + public static Path createProject(YuanMengOnlineService archetypeInfo) { + try { + // 配置项目目录 + Path projectDir = Files.createTempDirectory(archetypeInfo.getArchetypeArtifactId()); + log.info("项目生成目录: {}", projectDir); + + // 创建 settings.xml 文件 + Path settingsFile = createTempSettingsFile(); + + // 下面这行代码不能缺少,否则无法执行 + configureSystemProperties(settingsFile); + + // 使用 Maven Embedder 生成项目 + generateMavenProject(projectDir.toFile(), settingsFile, archetypeInfo); + + Path path = projectDir.resolve(archetypeInfo.getArchetypeArtifactId()); + log.info("✅ 项目成功创建于: {}", path); + return path; + } catch (Exception e) { + log.error("❌ 出现错误: {}, {}", e.getMessage(), archetypeInfo, e); + throw new RuntimeException("项目初始化失败:" + e.getMessage()); + } + } + + private static void generateMavenProject(File baseDir, Path settingsFile, YuanMengOnlineService archetypeInfo) { + // String[] argsClean = new String[]{ + // "-X", "dependency:resolve", "-s", settingsFile.getAbsolutePath() + // }; + // int i = new MavenCli().doMain(argsClean, baseDir.getAbsolutePath(), System.out, System.err); + + // boolean del = FileUtil.del("/tmp/repository"); + // log.info("delete tmp directory: {}", del); + + // 构建 Maven 参数 + String[] mvnArgs = new String[]{ + "archetype:generate", + "-DinteractiveMode=false", + "-DarchetypeGroupId=" + ARCHETYPE_GROUP_ID, + "-DarchetypeArtifactId=" + ARCHETYPE_ARTIFACT_ID, + "-DarchetypeVersion=" + ARCHETYPE_VERSION, + "-DgroupId=" + archetypeInfo.getArchetypeGroupId(), + "-DartifactId=" + archetypeInfo.getArchetypeArtifactId(), + "-Dversion=" + archetypeInfo.getArchetypeVersion(), + "-Dapp=" + archetypeInfo.getArchetypeApp(), + "-Dpackage=" + archetypeInfo.getArchetypePackage(), + "-B", // 开启批处理模式 + "-s", settingsFile.toString() + }; + + log.info("Maven 项目生成指令:{}", String.join(" ", mvnArgs)); + + // 使用 Maven Embedder + MavenCli cli = new MavenCli(); + int result = cli.doMain(mvnArgs, baseDir.getAbsolutePath(), System.out, System.err); + + if (result != 0) { + throw new RuntimeException("Maven 项目生成失败 (退出码: " + result + ")"); + } + + log.info("✅ Maven 项目生成成功"); + } + + private static Path createTempSettingsFile() { + try { + // 创建临时 settings.xml 文件 + Path settingsPath = Files.createTempFile("maven-settings", ".xml"); + + // 构建 settings.xml 内容 + String settingsContent = buildSettingsXml(); + + // 写入文件 + Files.write(settingsPath, settingsContent.getBytes()); + + // 设置文件删除钩子(程序退出时删除) + settingsPath.toFile().deleteOnExit(); + + return settingsPath; + } catch (IOException e) { + throw new RuntimeException("Failed to create temp settings.xml", e); + } + } + + private static String buildSettingsXml() { + return "\n" + + " /tmp/repository\n" + + " \n" + + " \n" + + " private-repo\n" + + " developer\n" + + " deve@123\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " private-repo\n" + + " Private Repository Mirror\n" + + " http://120.79.68.191:8081/repository/maven-public/\n" + + " *\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " default\n" + + " \n" + + " \n" + + " private-repo\n" + + " http://120.79.68.191:8081/repository/maven-public/\n" + + " true\n" + + " true\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " private-repo\n" + + " http://120.79.68.191:8081/repository/maven-public/\n" + + " true\n" + + " true\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " default\n" + + " \n" + + ""; + } + + private static void configureSystemProperties(Path settingsPath) { + System.setProperty("maven.multiModuleProjectDirectory", System.getProperty("user.dir")); + // 使用自定义 settings.xml + System.setProperty("maven.user.settings", settingsPath.toString()); + + // 配置超时(可选) + System.setProperty("maven.wagon.http.readTimeout", "300000"); // 5分钟 + System.setProperty("maven.wagon.http.connectionTimeout", "120000"); + + // 禁用 SSL 验证(如果私服使用 HTTP) + System.setProperty("maven.wagon.http.ssl.insecure", "true"); + System.setProperty("maven.wagon.http.ssl.allowall", "true"); + + // 启用调试日志(可选) + System.setProperty("org.slf4j.simpleLogger.log.org.apache.maven.cli", "info"); + } + +} +``` +---- +## Java操作Git及Gitlab +### 依赖引入 +```xml + + + + + org.eclipse.jgit + org.eclipse.jgit + 6.10.1.202505221210-r + + + + org.gitlab4j + gitlab4j-api + 5.3.0 + + +``` +### Java代码调用 +#### Gitlab调用工具类 +```java +package org.jeecg.modules.devops.archetype; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.gitlab4j.api.GitLabApi; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.models.*; + +import java.util.List; + +/** + * insert description here + * + * @author liuxiaohua + * @since 2025-06-11 + */ +@Slf4j +public class GitlabUtils { + + private static volatile GitLabApi gitLabApi; + + public static synchronized void init(ArchetypeProperties archetypeProperties) { + if (gitLabApi == null) { + synchronized (GitlabUtils.class) { + if (gitLabApi == null) { + gitLabApi = new GitLabApi(archetypeProperties.getGitlabUrl(), archetypeProperties.getAccessToken()); + } + } + } + } + + @SneakyThrows + public static void deleteProject(Long projectId) { + gitLabApi.getProjectApi().deleteProject(projectId); + } + + @SneakyThrows + public static Project createProject(String group, String project, String desc) { + Group groupInfo = getGroupId(group); + if (groupInfo == null || groupInfo.getId() == null) { + throw new RuntimeException("获取分组信息失败"); + } + Project gitLabRepository = createRepository(groupInfo.getId(), project, desc); + if (gitLabRepository == null || gitLabRepository.getId() == null) { + throw new RuntimeException("创建仓库失败"); + } + return gitLabRepository; + } + + @SneakyThrows + public static ProtectedBranch protectedBranch(Long projectId, Integer retryTimes) { + + try { + // 获取已保护的分支 + List protectedBranches = gitLabApi.getProtectedBranchesApi().getProtectedBranches(projectId); + log.info("protected branches: {}", JSONObject.toJSONString(protectedBranches)); + // 保护分支 + if (CollUtil.isNotEmpty(protectedBranches) + && protectedBranches.stream().map(ProtectedBranch::getName).anyMatch("master"::equalsIgnoreCase)) { + // 取消旧的配置 + unprotectedBranch(projectId); + } + // 添加分支保护 + return gitLabApi.getProtectedBranchesApi() + .protectBranch(projectId, "master", AccessLevel.NONE, AccessLevel.MAINTAINER); + } catch (GitLabApiException e) { + log.warn("protected branch failed: {}", e.getMessage()); + } + + if (retryTimes < 3) { + return protectedBranch(projectId, ++retryTimes); + } + log.warn("protected branch failure: {}", retryTimes); + throw new RuntimeException(ArchetypeUtils.WARN_MESSAGE_1); + } + + private static void unprotectedBranch(Long projectId) { + try { + gitLabApi.getProtectedBranchesApi().unprotectBranch(projectId, "master"); + log.info("unprotected branch master success"); + } catch (Exception e) { + log.warn("unprotected branch error: {}", e.getMessage()); + } + } + + /** + * 根据分组路径获取分组ID + */ + private static Group getGroupId(String groupPath) throws GitLabApiException { + return gitLabApi.getGroupApi().getGroup(groupPath); + } + + /** + * 在 GitLab 创建新仓库 + */ + private static Project createRepository(Long groupId, + String projectName, + String desc) { + try { + Project project = new Project() + .withName(projectName) + .withDefaultBranch("master") + .withDescription(desc) + .withNamespaceId(groupId) + .withVisibility(Visibility.PRIVATE); // 私有库用 PRIVATE + + return gitLabApi.getProjectApi().createProject(project); // 返回 HTTPS 仓库地址 + } catch (Exception e) { + log.warn("create project error: {}", e.getMessage()); + } + return null; + } + +} + +``` +#### Git调用工具类 +```java +package org.jeecg.modules.devops.archetype; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * insert description here + * + * @author liuxiaohua + * @since 2025-06-11 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GitUtils { + + /** + * 初始化本地仓库并推送到 GitLab + */ + public static void pushLocalCodeToGitLab(String remoteUrl, + String codePath, + ArchetypeProperties archetypeProperties) { + File localPath = new File(codePath); + CredentialsProvider credentials = new UsernamePasswordCredentialsProvider( + archetypeProperties.getUsername(), archetypeProperties.getAccessToken()); + + try (Git git = Git.init().setDirectory(localPath).call()) { + // 添加所有文件 + git.add().addFilepattern(".").call(); + + // 提交更改 + git.commit() + .setMessage(String.format("\uD83C\uDF89 [%s] 初始化提交", + new SimpleDateFormat("yyyy-MM-dd").format(new Date()))) + .call(); + + // 添加远程仓库 + git.remoteAdd() + .setName("origin") + .setUri(new URIish(remoteUrl)) + .call(); + + // 推送到 GitLab + git.push() + .setRemote("origin") + .setCredentialsProvider(credentials) + .setForce(true) + .setPushAll() + .call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} + +``` \ No newline at end of file