获取 GitLab API 访问令牌

  1. 登录到GitLab: 使用你的账号登录到GitLab实例中。
  2. 进入用户设置页面: 在右上角点击你的头像或用户头像,然后选择“Settings”或“Profile Settings”。
  3. 导航到Access Tokens页面: 在左侧菜单中找到“Access Tokens”选项(在GitLab的某些版本中,这个选项可能会被标记为“Personal Access Tokens”或在“Account”部分下方)。点击进入。
  4. 生成新的访问令牌:
    • 在“Name”字段中输入一个令牌的名称(可以是任意名称,描述它的用途)。
    • 在“Scopes”部分,选择适当的权限(例如“api”,以便你可以访问所有API功能)。
    • 点击“Create personal access token”。
  5. 保存令牌: GitLab会生成一个新的访问令牌。请注意,令牌只会显示一次,生成后务必立即复制并保存到安全的地方。稍后你就可以使用这个令牌来访问GitLab API。

导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class GitLabExporter {

// 新版本用 api/v4/projects

// 我的项目
// private static final String API_URL = "http://192.168.210.4:80/api/v3/projects";
// 所有项目
private static final String API_URL = "http://192.168.210.4:80/api/v3/projects/all";
private static final String TOKEN = "XnLD7shiefLjug5f9hgx"; // 替换为你的API访问令牌
private static final int PER_PAGE = 100; // 每页获取的项目数量

public static void main(String[] args) {
try {
String markdown = getAllProjectsMarkdown();
// System.out.println(markdown);
FileUtil.writeString(markdown, "D://all_projects.md", "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
}

private static String getAllProjectsMarkdown() throws IOException {
List<JsonNode> allProjects = new ArrayList<>();
int page = 1;
while (true) {
String url = API_URL + "?private_token=" + TOKEN + "&per_page=" + PER_PAGE + "&page=" + page;
HttpResponse response = HttpRequest.get(url).execute();
String body = response.body();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode projects = objectMapper.readTree(body);
if (projects.isEmpty()) break;
projects.forEach(allProjects::add);
page++;
}

System.out.println(allProjects.size());
return generateMarkdownTable(allProjects);
}

private static String generateMarkdownTable(List<JsonNode> projects) {
StringBuilder sb = new StringBuilder();
sb.append("| No. | Name | Description | URL |\n");
sb.append("|-----|------|-------------|-----|\n");

int index = 1;
for (JsonNode project : projects) {
String name = escapeMarkdown(project.path("name").asText());
String description = escapeMarkdown(project.path("description").asText("No description available"));
String url = escapeMarkdown(project.path("http_url_to_repo").asText());

sb.append(String.format("| %d | %s | %s | %s |\n", index, name, description, url));
index++;
}
return sb.toString();
}

private static String escapeMarkdown(String input) {
if (input == null) {
return "";
}
// 替换换行符和其他Markdown特定字符
return input
.replace("\n", " ") // 将换行符替换为空格
.replace("|", "\\|") // 转义竖线字符
.replaceAll("\\s+", " "); // 将多个连续空格替换为单个空格
}
}

导入

导出的markdown 转excel 导入到新的gitlab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
* gitlab api客户端
*
* @author shuzhuo
*/
public class GitLabApiClient {
private final String gitlabUrl;
private final String privateToken;

private final Map<String, String> groupNameMap = new HashMap<>();

public GitLabApiClient(String gitlabUrl, String privateToken) {
this.gitlabUrl = gitlabUrl;
this.privateToken = privateToken;
}

public String ensureGroupExists(String groupName) {
if (groupNameMap.containsKey(groupName)) {
String groupId = groupNameMap.get(groupName).trim();
if (StringUtils.isNotBlank(groupId)) {
return groupId;
}
}
String groupId = getGroupId(groupName);
if (groupId == null) {
groupId = createGroup(groupName);
groupNameMap.put(groupName, groupId);
}
return groupId;
}

private String getGroupId(String groupName) {
String url = gitlabUrl + "/api/v4/groups/" + groupName;
HttpResponse response = HttpRequest.get(url)
.header("PRIVATE-TOKEN", privateToken)
.execute();

if (response.getStatus() == 200) {
JSONObject jsonResponse = new JSONObject(response.body());
return jsonResponse.getStr("id");
}
return null;

}

private String createGroup(String groupName) {
String url = gitlabUrl + "/api/v4/groups";
JSONObject body = new JSONObject();
body.put("name", groupName);
body.put("path", groupName);

HttpResponse response = HttpRequest.post(url)
.header("PRIVATE-TOKEN", privateToken)
.body(body.toString())
.execute();

if (response.getStatus() == 201) {
JSONObject jsonResponse = new JSONObject(response.body());
String groupId = jsonResponse.getStr("id");
System.out.println("Group created successfully with ID: " + groupId);
return groupId;
} else {
System.err.println("Failed to create group: " + response.body());
return null;
}
}

public void ensureProjectExists(String projectName, String description, String groupId) {
// String projectId = getProjectId(projectName, groupId);
//if (projectId == null) {
createProject(projectName, description, groupId);
//}
}

private String getProjectId(String projectName, String groupId) {
String url = gitlabUrl + "/api/v4/projects?search=" + projectName;
HttpResponse response = HttpRequest.get(url)
.header("PRIVATE-TOKEN", privateToken)
.execute();

if (response.getStatus() == 200) {
if (response.body().equals("[]")) {
return null;
}
for (Object obj : new JSONArray(response.body())) {
JSONObject project = new JSONObject(obj);
// if (project.getStr("namespace_id").equals(groupId)) {
return project.getStr("id");
// }
}
}
return null;
}

private void createProject(String projectName, String description, String groupId) {
String url = gitlabUrl + "/api/v4/projects";
JSONObject body = new JSONObject();
body.put("name", projectName);
body.put("description", description);
body.put("namespace_id", groupId);

HttpResponse response = HttpRequest.post(url)
.header("PRIVATE-TOKEN", privateToken)
.body(body.toString())
.execute();

if (response.getStatus() == 201) {
JSONObject jsonResponse = new JSONObject(response.body());
String projectId = jsonResponse.getStr("id");
System.out.println("Project created successfully with ID: " + projectId);
} else {
System.err.println("Failed to create project: " + response.body());
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RuntimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
* git处理程序
*
* @author shuzhuo
*/
@Slf4j
public class GitHandler {

/**
* 签出目录
*/
private final String checkoutDirectory;

public GitHandler(String checkoutDirectory) {
this.checkoutDirectory = checkoutDirectory;
}


/**
* 克隆存储库
*
* @param gitUrl git url
* @param name 名称
* @throws Exception 例外
*/
public void cloneRepository(String gitUrl, String name) throws Exception {
String gitUrl2 = "http://root:XpaKdb4Fjy2609@" + gitUrl.replace("http://", "");
log.info("cloneRepository gitUrl: {}", gitUrl2);
executeGitClone(gitUrl2, name);

}

/**
* 推送到新存储库
*
* @param projectName 项目名称
* @param newGitUrl 新git url
* @throws IOException IOException
* @throws InterruptedException 中断异常
*/
public void pushToNewRepository(String projectName, String newGitUrl) throws IOException, InterruptedException {
String gitUrl = "http://root:glpat-ssMtpGJRMTn1NLFvpwAC@" + newGitUrl.replace("http://", "");
log.info("pushToNewRepository gitUrl: {}", gitUrl);
executeGitPush(gitUrl, projectName);
}

public void executeGitClone(String gitUrl, String name) throws Exception {
String fileName = String.format("%s%s", checkoutDirectory, name);
File file = new File(fileName);
if (file.exists()) {
log.info("{} already exists", fileName);
return;
}
// 构建命令
String command = String.format("git clone --bare %s %s", gitUrl, fileName);
log.info("executeGitClone command: {}", command);

Process exec = RuntimeUtil.exec(command);
int pid = RuntimeUtil.getPid();
log.info("executeGitClone pid: {}", pid);
exec.waitFor(120, TimeUnit.SECONDS);
log.info("executeGitClone exitValue: {}", exec.exitValue());
String result = RuntimeUtil.getResult(exec, CharsetUtil.systemCharset());
log.info("executeGitClone result: {}", result);
ThreadUtil.sleep(3000);
}


/**
* 执行git推送
*
* @param newGitUrl 新git url
* @param projectName 项目名称
* @throws InterruptedException 中断异常
*/
public void executeGitPush(String newGitUrl, String projectName) throws InterruptedException {
// 构建命令
String ss = String.format("cd /d %s%s && git push --mirror %s", checkoutDirectory, projectName, newGitUrl);
String[] command = {
"cmd.exe", "/c", ss
};
log.info("executeGitPush command: {}", StringUtils.join(command, ","));
Process exec = RuntimeUtil.exec(command);
exec.waitFor(120, TimeUnit.SECONDS);
log.info("executeGitPush exitValue: {}", exec.exitValue());
String result = RuntimeUtil.getResult(exec, CharsetUtil.systemCharset());
log.info("executeGitPush result: {}", result);
ThreadUtil.sleep(3000);
}
}

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class GitMigrationTool {


@SneakyThrows
public static void main(String[] args) {
String excelFilePath = "C:\\Users\\shuzhuo\\Desktop\\111.xlsx";
String gitlabUrl = "http://192.168.210.4";
String privateToken = "glpat-ssMtpGJRMTn1NLFvpwAC";
String checkoutDirectory = "d://data/checkout/";

List<GitRepositoryInfo> gitRepositoryInfos = readExcel(excelFilePath);

GitLabApiClient gitLabApiClient = new GitLabApiClient(gitlabUrl, privateToken);
GitHandler gitHandler = new GitHandler(checkoutDirectory);

for (GitRepositoryInfo repoInfo : gitRepositoryInfos) {
log.info("Processing repository: {}", repoInfo.getName());
try {
// 1. 克隆旧的 Git 仓库
log.info("Cloning repository from {}", repoInfo.getOldGitUrl());
gitHandler.cloneRepository(repoInfo.getOldGitUrl(), repoInfo.getName());

// 2. 确保群组存在
log.info("Ensuring group {} exists", repoInfo.getGroupName());
String groupId = gitLabApiClient.ensureGroupExists(repoInfo.getGroupName());

// 3. 确保项目存在
log.info("Ensuring project {} exists", repoInfo.getName());
gitLabApiClient.ensureProjectExists(repoInfo.getName(), repoInfo.getDescription(), groupId);

// 4. 推送到新的 Git 仓库
String newGitUrl = gitlabUrl + "/" + repoInfo.getGroupName() + "/" + repoInfo.getName() + ".git";
log.info("Pushing to new repository {}", newGitUrl);
gitHandler.pushToNewRepository(repoInfo.getName(), newGitUrl);
log.info("Repository {} processed successfully", repoInfo.getName());

} catch (IOException | InterruptedException e) {
log.error("Error processing repository {}", repoInfo.getName(), e);
e.printStackTrace();
}
}
}

/**
* 读取excel
*
* @param filePath 文件路径
* @return {@link List }<{@link GitRepositoryInfo }>
*/
public static List<GitRepositoryInfo> readExcel(String filePath) {
ExcelReader reader = ExcelUtil.getReader(filePath);
List<GitRepositoryInfo> gitRepositoryInfos = new ArrayList<>();

List<List<Object>> readAll = reader.read(1); // 跳过第一行标题行
for (List<Object> row : readAll) {
String name = row.get(0).toString();
String description = row.get(1).toString();
String oldGitUrl = row.get(2).toString();
String groupName = row.get(3).toString();

gitRepositoryInfos.add(new GitRepositoryInfo(name, description, oldGitUrl, groupName));
}

return gitRepositoryInfos;
}
}