feat(project): 重构 通过私人令牌导入仓库

This commit is contained in:
魏宏斌 2023-03-26 11:32:35 +08:00
parent 3618d8e188
commit bf4ecb3499
No known key found for this signature in database
GPG Key ID: 6B1033008CD0A8BE
16 changed files with 519 additions and 927 deletions

View File

@ -24,7 +24,6 @@ package io.jpom.controller.build;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
@ -32,15 +31,13 @@ import cn.hutool.core.util.URLUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import io.jpom.build.BuildUtil;
import io.jpom.common.BaseServerController;
import io.jpom.common.JsonMessage;
import io.jpom.common.ServerConst;
import io.jpom.common.validator.ValidatorItem;
import io.jpom.controller.build.repository.*;
import io.jpom.controller.build.repository.ImportRepoUtil;
import io.jpom.model.data.RepositoryModel;
import io.jpom.model.enums.GitProtocolEnum;
import io.jpom.permission.ClassFeature;
@ -50,7 +47,6 @@ import io.jpom.plugin.IPlugin;
import io.jpom.plugin.PluginFactory;
import io.jpom.service.dblog.BuildInfoService;
import io.jpom.service.dblog.RepositoryService;
import io.jpom.system.JpomRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -197,6 +193,13 @@ public class RepositoryController extends BaseServerController {
return new JsonMessage<>(200, "操作成功");
}
@GetMapping(value = "/build/repository/provider_info")
@Feature(method = MethodFeature.LIST)
public JsonMessage<Map<String, Map<String, Object>>> providerInfo() {
Map<String, Map<String, Object>> providerList = ImportRepoUtil.getProviderList();
return JsonMessage.success(HttpStatus.OK.name(), providerList);
}
@GetMapping(value = "/build/repository/authorize_repos")
@Feature(method = MethodFeature.LIST)
public JsonMessage<PageResultDto<JSONObject>> authorizeRepos(HttpServletRequest request,
@ -208,258 +211,25 @@ public class RepositoryController extends BaseServerController {
Map<String, String> paramMap = ServletUtil.getParamMap(request);
Page page = repositoryService.parsePage(paramMap);
Assert.hasText(token, "请填写个人令牌");
//String gitlabAddress = StrUtil.blankToDefault(paramMap.get("gitlabAddress"), "https://gitlab.com");
//String giteaAddress = paramMap.get("giteaAddress");
// 搜索条件
// 远程仓库
PageResultDto<JSONObject> pageResultDto;
switch (type) {
case "gitee":
pageResultDto = this.giteeRepos(token, page, condition, request);
break;
case "github":
// GitHub 不支持条件搜索
pageResultDto = this.githubRepos(token, page, request);
break;
case "gitlab":
pageResultDto = this.gitlabRepos(token, page, condition, address, request);
break;
case "gitea":
pageResultDto = this.giteaRepos(token, page, condition, address, request);
break;
case "gogs":
pageResultDto = this.gogsRepos(token, page, condition, address, request);
break;
default:
throw new IllegalArgumentException("不支持的类型");
}
ImportRepoUtil.getProviderConfig(type);
String userName = ImportRepoUtil.getCurrentUserName(type, token, address);
cn.hutool.json.JSONObject repoList = ImportRepoUtil.getRepoList(type, condition, page, token, userName, address);
pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), repoList.getLong("total").intValue());
List<JSONObject> objects = repoList.getJSONArray("data").stream().map(o -> {
cn.hutool.json.JSONObject obj = (cn.hutool.json.JSONObject) o;
JSONObject jsonObject = new JSONObject();
jsonObject.putAll(obj);
jsonObject.put("exists", RepositoryController.this.checkRepositoryUrl(obj.getStr("url"), request));
return jsonObject;
}).collect(Collectors.toList());
pageResultDto.setResult(objects);
return JsonMessage.success(HttpStatus.OK.name(), pageResultDto);
}
/**
* gitlab 仓库
* <p>
* <a href="https://docs.gitlab.com/ee/api/projects.html#list-all-projects">https://docs.gitlab.com/ee/api/projects.html#list-all-projects</a>
*
* @param token 个人令牌
* @param page 分页
* @param gitlabAddress gitLab 地址
* @return page
*/
private PageResultDto<JSONObject> gitlabRepos(String token, Page page, String condition, String gitlabAddress, HttpServletRequest request) {
gitlabAddress = StrUtil.blankToDefault(gitlabAddress, "https://gitlab.com");
// 删除最后的 /
if (gitlabAddress.endsWith("/")) {
gitlabAddress = gitlabAddress.substring(0, gitlabAddress.length() - 1);
}
// 内部自建 GitLab一般都没有配置 https 协议如果用户没有指定协议默认走 httpgitlab https
// https 访问不了的情况下自动替换为 http
if (!StrUtil.startWithAnyIgnoreCase(gitlabAddress, "http://", "https://")) {
gitlabAddress = "http://" + gitlabAddress;
}
HttpResponse userResponse = null;
try {
userResponse = GitLabUtil.getGitLabUserInfo(gitlabAddress, token);
} catch (IORuntimeException ioRuntimeException) {
// 连接超时切换至 http 协议进行重试
if (StrUtil.startWithIgnoreCase(gitlabAddress, "https")) {
gitlabAddress = "http" + gitlabAddress.substring(5);
userResponse = GitLabUtil.getGitLabUserInfo(gitlabAddress, token);
}
Assert.state(userResponse != null, "无法连接至 GitLab" + ioRuntimeException.getMessage());
}
Assert.state(userResponse.isOk(), "令牌不正确:" + userResponse.body());
JSONObject userBody = JSONObject.parseObject(userResponse.body());
String username = userBody.getString("username");
Map<String, Object> gitLabRepos = GitLabUtil.getGitLabRepos(gitlabAddress, token, page, condition);
JSONArray jsonArray = JSONArray.parseArray((String) gitLabRepos.get("body"));
List<JSONObject> objects = jsonArray.stream().map(o -> {
JSONObject repo = (JSONObject) o;
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", repo.getString("name"));
String htmlUrl = repo.getString("http_url_to_repo");
jsonObject.put("url", htmlUrl);
jsonObject.put("full_name", repo.getString("path_with_namespace"));
// visibility 有三种public, internal, or private. public都是 private
jsonObject.put("private", !StrUtil.equalsIgnoreCase("public", repo.getString("visibility")));
jsonObject.put("description", repo.getString("description"));
jsonObject.put("username", username);
jsonObject.put("exists", RepositoryController.this.checkRepositoryUrl(htmlUrl, request));
return jsonObject;
}).collect(Collectors.toList());
PageResultDto<JSONObject> pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), (int) gitLabRepos.get("total"));
pageResultDto.setResult(objects);
return pageResultDto;
}
/**
* github 仓库
*
* @param token 个人令牌
* @param page 分页
* @return page
*/
private PageResultDto<JSONObject> githubRepos(String token, Page page, HttpServletRequest request) {
GitHubUtil.GitHubUserInfo gitHubUserInfo = GitHubUtil.getGitHubUserInfo(token);
JSONArray gitHubUserReposArray = GitHubUtil.getGitHubUserRepos(token, page);
List<JSONObject> objects = gitHubUserReposArray.stream().map(o -> {
JSONObject repo = (JSONObject) o;
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", repo.getString("name"));
String cloneUrl = repo.getString("clone_url");
jsonObject.put("url", cloneUrl);
jsonObject.put("full_name", repo.getString("full_name"));
jsonObject.put("description", repo.getString("description"));
jsonObject.put("private", repo.getBooleanValue("private"));
//
jsonObject.put("username", gitHubUserInfo.getLogin());
jsonObject.put("exists", RepositoryController.this.checkRepositoryUrl(cloneUrl, request));
return jsonObject;
}).collect(Collectors.toList());
//
PageResultDto<JSONObject> pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), gitHubUserInfo.public_repos);
pageResultDto.setResult(objects);
return pageResultDto;
}
/**
* gitee 仓库
*
* @param token 个人令牌
* @param page 分页
* @return page
*/
private PageResultDto<JSONObject> giteeRepos(String token, Page page, String condition, HttpServletRequest request) {
String giteeUsername = GiteeUtil.getGiteeUsername(token);
Map<String, Object> giteeReposMap = GiteeUtil.getGiteeRepos(token, page, condition);
JSONArray jsonArray = (JSONArray) giteeReposMap.get("jsonArray");
int totalCount = (int) giteeReposMap.get("totalCount");
List<JSONObject> objects = jsonArray.stream().map(o -> {
JSONObject repo = (JSONObject) o;
JSONObject jsonObject = new JSONObject();
// 项目名称Jpom
jsonObject.put("name", repo.getString("name"));
// 项目地址https://gitee.com/dromara/Jpom.git
String htmlUrl = repo.getString("html_url");
jsonObject.put("url", htmlUrl);
// 所属者/项目名dromara/Jpom
jsonObject.put("full_name", repo.getString("full_name"));
// 是否为私有仓库是私有仓库为 true非私有仓库为 false
jsonObject.put("private", repo.getBooleanValue("private"));
// 项目描述简而轻的低侵入式在线构建自动部署日常运维项目监控软件
jsonObject.put("description", repo.getString("description"));
jsonObject.put("username", giteeUsername);
jsonObject.put("exists", this.checkRepositoryUrl(htmlUrl, request));
return jsonObject;
}).collect(Collectors.toList());
PageResultDto<JSONObject> pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), totalCount);
pageResultDto.setResult(objects);
return pageResultDto;
}
/**
* gogo仓库
*
* @param token 个人令牌
* @param page 分页
* @return page
*/
private PageResultDto<JSONObject> gogsRepos(String token, Page page, String condition, String giteaAddress, HttpServletRequest request) {
Assert.hasText(giteaAddress, "请填写 gogs 地址");
String gogsUsername = GogsUtil.getUsername(giteaAddress, token);
Map<String, Object> giteaReposMap = GiteaUtil.getRepos(giteaAddress, token, page, condition);
JSONArray jsonArray = (JSONArray) giteaReposMap.get("jsonArray");
int totalCount = (int) giteaReposMap.get("totalCount");
List<JSONObject> objects = jsonArray.stream().map(o -> {
JSONObject repo = (JSONObject) o;
JSONObject jsonObject = new JSONObject();
// 项目名称Jpom
jsonObject.put("name", repo.getString("name"));
// 项目地址https://10.0.0.1:3000/dromara/Jpom.git
String htmlUrl = repo.getString("html_url");
jsonObject.put("url", htmlUrl);
// 所属者/项目名dromara/Jpom
jsonObject.put("full_name", repo.getString("full_name"));
// 是否为私有仓库是私有仓库为 true非私有仓库为 false
jsonObject.put("private", repo.getBooleanValue("private"));
// 项目描述简而轻的低侵入式在线构建自动部署日常运维项目监控软件
jsonObject.put("description", repo.getString("description"));
jsonObject.put("username", gogsUsername);
jsonObject.put("exists", this.checkRepositoryUrl(htmlUrl, request));
return jsonObject;
}).collect(Collectors.toList());
PageResultDto<JSONObject> pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), totalCount);
pageResultDto.setResult(objects);
return pageResultDto;
}
/**
* gitea仓库
*
* @param token 个人令牌
* @param page 分页
* @return page
*/
private PageResultDto<JSONObject> giteaRepos(String token, Page page, String condition, String giteaAddress, HttpServletRequest request) {
Assert.hasText(giteaAddress, "请填写 gitea 地址");
String giteaUsername = GiteaUtil.getUsername(giteaAddress, token);
Map<String, Object> giteaReposMap = GiteaUtil.getRepos(giteaAddress, token, page, condition);
JSONArray jsonArray = (JSONArray) giteaReposMap.get("jsonArray");
int totalCount = (int) giteaReposMap.get("totalCount");
List<JSONObject> objects = jsonArray.stream().map(o -> {
JSONObject repo = (JSONObject) o;
JSONObject jsonObject = new JSONObject();
// 项目名称Jpom
jsonObject.put("name", repo.getString("name"));
// 项目地址https://10.0.0.1:3000/dromara/Jpom.git
String htmlUrl = repo.getString("html_url");
jsonObject.put("url", htmlUrl);
// 所属者/项目名dromara/Jpom
jsonObject.put("full_name", repo.getString("full_name"));
// 是否为私有仓库是私有仓库为 true非私有仓库为 false
jsonObject.put("private", repo.getBooleanValue("private"));
// 项目描述简而轻的低侵入式在线构建自动部署日常运维项目监控软件
jsonObject.put("description", repo.getString("description"));
jsonObject.put("username", giteaUsername);
jsonObject.put("exists", this.checkRepositoryUrl(htmlUrl, request));
return jsonObject;
}).collect(Collectors.toList());
PageResultDto<JSONObject> pageResultDto = new PageResultDto<>(page.getPageNumber(), page.getPageSize(), totalCount);
pageResultDto.setResult(objects);
return pageResultDto;
}
/**
* 检查信息
*

View File

@ -1,125 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import cn.hutool.db.Page;
import cn.hutool.http.Header;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import org.springframework.util.Assert;
/**
* GitHub 工具
*
* @author sam
* @since 2023/3/9
*/
public class GitHubUtil {
/**
* GitHub 用户信息实体类
* <p>
* 参考https://docs.github.com/en/rest/users/users#about-the-users-api
*/
@Data
public static class GitHubUserInfo {
// 只列出目前需要用到的字段
/**
* 用户名octocat
*/
private String login;
/**
* 公开仓库数量2
*/
public int public_repos;
/**
* 私有的仓库总数100
*/
public int total_private_repos;
/**
* 拥有的私有仓库100
*/
public int owned_private_repos;
}
/**
* GitHub 头部
*/
private static final String GITHUB_HEADER_ACCEPT = "application/vnd.github.v3+json";
/**
* GitHub 用户 token 前缀
*/
private static final String GITHUB_TOKEN = "token ";
/**
* GitHub API 前缀
*/
private static final String GITHUB_API_PREFIX = "https://api.github.com";
/**
* 获取 GitHub 用户信息
*
* @param token 用户 token
* @return GitHub 用户信息
*/
public static GitHubUserInfo getGitHubUserInfo(String token) {
// 参考https://docs.github.com/en/rest/users/users#about-the-users-api
HttpResponse response = HttpUtil
.createGet(GITHUB_API_PREFIX + "/user")
.header(Header.ACCEPT, GITHUB_HEADER_ACCEPT)
.header(Header.AUTHORIZATION, GITHUB_TOKEN + token)
.execute();
String body = response.body();
Assert.state(response.isOk(), "令牌信息错误:" + body);
return JSONObject.parseObject(body, GitHubUserInfo.class);
}
/**
* 获取 GitHub 仓库信息
*
* @param token
*/
public static JSONArray getGitHubUserRepos(String token, Page page) {
// 参考https://docs.github.com/en/rest/repos/repos#list-repositories-for-the-authenticated-user
HttpResponse response = HttpUtil
.createGet(GITHUB_API_PREFIX + "/user/repos")
.header(Header.ACCEPT, GITHUB_HEADER_ACCEPT)
.header(Header.AUTHORIZATION, GITHUB_TOKEN + token)
.form("access_token", token)
.form("sort", "pushed")
.form("page", page.getPageNumber())
.form("per_page", page.getPageSize())
.execute();
String body = response.body();
Assert.state(response.isOk(), "拉取仓库信息错误:" + body);
return JSONArray.parseArray(body);
}
}

View File

@ -1,193 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Page;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import lombok.Data;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* GitLab 工具
*
* @author sam
* @since 2023/3/9
*/
public class GitLabUtil {
/**
* GitLab 版本号信息参考https://docs.gitlab.com/ee/api/version.html
*/
@Data
private static class GitLabVersionInfo {
/**
* 版本号8.13.0-pre
*/
private String version;
/**
* 修订号4e963fe
*/
private String revision;
/**
* API 版本号v4
*/
private String apiVersion;
}
/**
* GitLab 版本信息容器keyGitLab 地址valueGitLabVersionInfo
*/
public static final Map<String, GitLabVersionInfo> gitlabVersionMap = new ConcurrentHashMap<>();
/**
* 获取 GitLab 版本
*
* @param gitlabAddress GitLab 地址
* @param token 用户 token
* @return 请求结果
*/
public static HttpResponse getGitLabVersion(String gitlabAddress, String token, String apiVersion) {
// 参考https://docs.gitlab.com/ee/api/version.html
return HttpUtil.createGet(StrUtil.format("{}/api/{}/version", gitlabAddress, apiVersion), true)
.header("PRIVATE-TOKEN", token)
.execute();
}
/**
* 获取 GitLab 版本信息
*
* @param url GitLab 地址
* @param token 用户 token
*/
public static GitLabVersionInfo getGitLabVersionInfo(String url, String token) {
// 缓存中有的话从缓存读取
GitLabVersionInfo gitLabVersionInfo = gitlabVersionMap.get(url);
if (gitLabVersionInfo != null) {
return gitLabVersionInfo;
}
// 获取 GitLab 版本号信息
GitLabVersionInfo glvi = null;
String apiVersion = "v4";
HttpResponse v4 = getGitLabVersion(url, token, apiVersion);
if (v4 != null) {
glvi = JSON.parseObject(v4.body(), GitLabVersionInfo.class);
} else {
apiVersion = "v3";
HttpResponse v3 = getGitLabVersion(url, token, apiVersion);
if (v3 != null) {
glvi = JSON.parseObject(v3.body(), GitLabVersionInfo.class);
}
}
Assert.state(glvi != null, "获取 GitLab 版本号失败,请检查 GitLab 地址和 token 是否正确");
// 添加到缓存中
glvi.setApiVersion(apiVersion);
gitlabVersionMap.put(url, glvi);
return glvi;
}
/**
* 获取 GitLab API 版本号
*
* @param url GitLab 地址
* @param token 用户 token
* @return GitLab API 版本号v4
*/
public static String getGitLabApiVersion(String url, String token) {
return getGitLabVersionInfo(url, token).getApiVersion();
}
/**
* 获取 GitLab 用户信息
*
* @param gitlabAddress GitLab 地址
* @param token 用户 token
* @return 请求结果
*/
public static HttpResponse getGitLabUserInfo(String gitlabAddress, String token) {
// 参考https://docs.gitlab.com/ee/api/users.html
return HttpUtil.createGet(
StrUtil.format(
"{}/api/{}/user",
gitlabAddress,
getGitLabApiVersion(gitlabAddress, token)
), true
)
.form("access_token", token)
.timeout(5000)
.execute();
}
/**
* 获取 GitLab 仓库信息
*
* @param gitlabAddress GitLab 地址
* @param token 用户 token
* @return 响应结果
*/
public static Map<String, Object> getGitLabRepos(String gitlabAddress, String token, Page page, String condition) {
// 参考https://docs.gitlab.com/ee/api/projects.html
HttpResponse reposResponse = HttpUtil.createGet(
StrUtil.format(
"{}/api/{}/projects",
gitlabAddress,
getGitLabApiVersion(gitlabAddress, token)
), true
)
.form("private_token", token)
.form("membership", true)
// simple=true 不返回项目的 visibility无法判断是私有仓库公开仓库还是内部仓库
// .form("simple", true)
.form("order_by", "updated_at")
.form("page", page.getPageNumber())
.form("per_page", page.getPageSize())
.form("search", condition)
.execute();
String body = reposResponse.body();
Assert.state(reposResponse.isOk(), "拉取仓库信息错误:" + body);
String totalCountStr = reposResponse.header("X-Total");
int totalCount = Convert.toInt(totalCountStr, 0);
//String totalPage = reposResponse.header("total_page");
Map<String, Object> map = new HashMap<>(2);
map.put("body", body);
map.put("total", totalCount);
return map;
}
}

View File

@ -1,153 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import cn.hutool.core.convert.Convert;
import cn.hutool.db.Page;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
/**
* Gitea 工具
*
* @author songxinqiang
* @since 2023/3/9
*/
public class GiteaUtil {
/**
* Gitea API 版本号
*/
private static final String API_VERSION = "v1";
/**
* 用户授权码
*/
private static final String ACCESS_TOKEN = "access_token";
/**
* 排序方式: 创建时间(created)更新时间(updated)最后推送时间(pushed)仓库所属与名称(full_name)默认: full_name
*/
private static final String SORT = "sort";
/**
* 当前的页码
*/
private static final String PAGE = "page";
/**
* 每页的数量最大为 100
*/
private static final String LIMIT = "limit";
/**
* 获取 Gitea 用户名
*
* @param token 用户授权码
* @return Gitea 用户名
*/
public static String getUsername(String giteaAddress, String token) {
HttpResponse userResponse = HttpUtil.createGet(giteaAddress + "/api/v1/user", true)
.form(ACCESS_TOKEN, token)
.execute();
Assert.state(userResponse.isOk(), "令牌不正确:" + userResponse.body());
JSONObject userBody = JSONObject.parseObject(userResponse.body());
return userBody.getString("login");
}
/**
* 获取 Gitea 用户仓库信息
*
* @param giteaAddress Gitea 地址
* @param token 用户授权码
* @param page 分页参数
* @return map
*/
public static Map<String, Object> getRepos(String giteaAddress, String token, Page page, String condition) {
if (condition == null) {
HttpResponse reposResponse = HttpUtil.createGet(giteaAddress + "/api/v1/user/repos", true)
.form(ACCESS_TOKEN, token)
//.form(SORT, "newest")
.form(PAGE, page.getPageNumber())
.form(LIMIT, page.getPageSize())
// 搜索关键字
//.form("q", condition)
.execute();
String body = reposResponse.body();
Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + body);
// 所有仓库总数包括公开的和私有的
String totalCountStr = reposResponse.header("x-total-count");
int totalCount = Convert.toInt(totalCountStr, 0);
//String totalPage = reposResponse.header("total_page");
Map<String, Object> map = new HashMap<>(2);
map.put("jsonArray", JSONArray.parseArray(body));
// 仓库总数
map.put("totalCount", totalCount);
return map;
} else {
return getGiteaReposSearch(giteaAddress, token, page, condition);
}
}
/**
* 获取 Gitea 用户仓库信息搜索
*
* @param giteaAddress Gitea 地址
* @param token 用户授权码
* @param page 分页参数
* @return
*/
public static Map<String, Object> getGiteaReposSearch(String giteaAddress, String token, Page page, String condition) {
HttpResponse reposResponse = HttpUtil.createGet(giteaAddress + "/api/v1/repos/search", true)
.form(ACCESS_TOKEN, token)
.form(SORT, "created")
.form(PAGE, page.getPageNumber())
.form(LIMIT, page.getPageSize())
// 搜索关键字
.form("q", condition)
.execute();
String body = reposResponse.body();
JSONObject jsonObject = JSON.parseObject(body);
JSONArray data = jsonObject.getJSONArray("data");
Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + data.toString());
// 所有仓库总数包括公开的和私有的
String totalCountStr = reposResponse.header("x-total-count");
int totalCount = Convert.toInt(totalCountStr, 0);
Map<String, Object> map = new HashMap<>(2);
map.put("jsonArray", JSONArray.parseArray(data.toString()));
// 仓库总数
map.put("totalCount", totalCount);
return map;
}
}

View File

@ -1,126 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import cn.hutool.core.convert.Convert;
import cn.hutool.db.Page;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
/**
* Gitee 工具
*
* @author sam
* @since 2023/3/9
*/
public class GiteeUtil {
/**
* Gitee API 前缀
*/
private static final String GITEE_API_PREFIX = "https://gitee.com/api";
/**
* Gitee API 版本号
*/
private static final String API_VERSION = "v5";
/**
* Gitee API 地址前缀
*/
private static final String GITEE_API_URL_PREFIX = GITEE_API_PREFIX + "/" + API_VERSION;
/**
* 用户授权码
*/
private static final String ACCESS_TOKEN = "access_token";
/**
* 排序方式: 创建时间(created)更新时间(updated)最后推送时间(pushed)仓库所属与名称(full_name)默认: full_name
*/
private static final String SORT = "sort";
/**
* 当前的页码
*/
private static final String PAGE = "page";
/**
* 每页的数量最大为 100
*/
private static final String PER_PAGE = "per_page";
/**
* 获取 Gitee 用户名
*
* @param token 用户授权码
* @return Gitee 用户名
*/
public static String getGiteeUsername(String token) {
// 参考https://gitee.com/api/v5/swagger#/getV5User
HttpResponse userResponse = HttpUtil.createGet(GITEE_API_URL_PREFIX + "/user", true)
.form(ACCESS_TOKEN, token)
.execute();
Assert.state(userResponse.isOk(), "令牌不正确:" + userResponse.body());
JSONObject userBody = JSONObject.parseObject(userResponse.body());
return userBody.getString("login");
}
/**
* 获取 Gitee 用户仓库信息
*
* @param token 用户授权码
* @param page 分页参数
* @return
*/
public static Map<String, Object> getGiteeRepos(String token, Page page, String condition) {
// 参考https://gitee.com/api/v5/swagger#/getV5UserRepos
HttpResponse reposResponse = HttpUtil.createGet(GITEE_API_URL_PREFIX + "/user/repos", true)
.form(ACCESS_TOKEN, token)
.form(SORT, "pushed")
.form(PAGE, page.getPageNumber())
.form(PER_PAGE, page.getPageSize())
// 搜索关键字
.form("q", condition)
.execute();
String body = reposResponse.body();
Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + body);
// 所有仓库总数包括公开的和私有的
String totalCountStr = reposResponse.header("total_count");
int totalCount = Convert.toInt(totalCountStr, 0);
//String totalPage = reposResponse.header("total_page");
Map<String, Object> map = new HashMap<>(2);
map.put("jsonArray", JSONArray.parseArray(body));
// 仓库总数
map.put("totalCount", totalCount);
return map;
}
}

View File

@ -1,30 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
/**
* @author bwcx_jzy
* @since 2023/3/19
*/
public class GogsUtil extends GiteaUtil {
}

View File

@ -0,0 +1,94 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import lombok.Data;
import java.util.Map;
/**
* 仓库提供商配置
*
* @author WeiHongBin
*/
@Data
public class ImportRepoProviderConfig {
private String baseUrl;
/**
* 鉴权方式 1:header 2:from 3:body
*/
private Integer authType;
/**
* 鉴权key 例如Authorization
*/
private String authKey;
/**
* 鉴权值 例如Bearer ${token}
*/
private String authValue;
/**
* 扩展参数
*/
private Map<String, String> extraParams;
/**
* 扩展参数类型 1:header 2:from 3:body
*/
private Integer extraParamsType;
/**
* 获取用户信息的请求方式
*/
private String currentUserMethod;
/**
* 获取用户信息的请求地址
*/
private String currentUserUrl;
/**
* 获取用户名 path
*/
private String userNamePath;
/**
* 获取仓库列表的请求方式
*/
private String repoListMethod;
/**
* 获取仓库列表的请求地址
*/
private String repoListUrl;
/**
* 获取仓库列表的请求参数
*/
private Map<String, String> repoListParam;
/**
* 获取仓库列表数组 path
*/
private String repoListPath;
/**
* 仓库信息 转换 path
*/
private Map<String, String> repoConvertPath;
/**
* 获取仓库总数 X-Total
*/
private String repoTotalHeader;
}

View File

@ -0,0 +1,206 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.jpom.controller.build.repository;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Page;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.setting.yaml.YamlUtil;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@UtilityClass
public class ImportRepoUtil {
private static final String IMPORT_REPO_PROVIDER_DIR = "/import-repo-provider";
@SneakyThrows
public Map<String, Map<String, Object>> getProviderList() {
String normalize = FileUtil.normalize(IMPORT_REPO_PROVIDER_DIR);
ClassPathResource classPathResource = new ClassPathResource(normalize);
if (!classPathResource.exists()) {
return null;
}
return Arrays.stream(Objects.requireNonNull(classPathResource.getFile()
.listFiles(pathname -> StrUtil.endWith(pathname.getName(), ".yml"))))
.map(file -> {
String name = file.getName().replace(".yml", "");
ImportRepoProviderConfig providerConfig = getProviderConfig(name);
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("baseUrl", providerConfig.getBaseUrl());
// 是否支持查询
map.put("query", providerConfig.getRepoListParam().values().stream().anyMatch(s -> s.contains("${query}")));
return map;
}).collect(Collectors.toMap(map -> (String) map.get("name"), map -> map));
}
@SneakyThrows
public ImportRepoProviderConfig getProviderConfig(String platform) {
String normalize = FileUtil.normalize(String.format("%s/%s.yml", IMPORT_REPO_PROVIDER_DIR, platform));
ClassPathResource classPathResource = new ClassPathResource(normalize);
Assert.state(classPathResource.exists(), "配置文件不存在");
try (InputStream inputStream = classPathResource.getInputStream()) {
return YamlUtil.load(inputStream, ImportRepoProviderConfig.class);
}
}
private void setCommonParams(String platform, HttpRequest request, String token) {
ImportRepoProviderConfig provider = getProviderConfig(platform);
String callToken = provider.getAuthValue().replace("${token}", token);
if (provider.getAuthType() == 1) {
request.header(provider.getAuthKey(), callToken);
} else if (provider.getAuthType() == 2) {
request.form(provider.getAuthKey(), callToken);
} else if (provider.getAuthType() == 3) {
request.body(JSONUtil.createObj().set(provider.getAuthKey(), callToken).toString());
}
Map<String, String> extraParams = provider.getExtraParams();
if (CollUtil.isNotEmpty(extraParams)) {
if (provider.getExtraParamsType() == 1) {
extraParams.forEach(request::header);
} else if (provider.getExtraParamsType() == 2) {
extraParams.forEach(request::form);
} else if (provider.getExtraParamsType() == 3) {
request.body(JSONUtil.toJsonStr(extraParams));
}
}
}
public JSONObject getRepoList(String platform, String query, Page page, String token, String username, String baseUrl) {
baseUrl = StrUtil.blankToDefault(baseUrl, getProviderConfig(platform).getBaseUrl());
ImportRepoProviderConfig provider = getProviderConfig(platform);
HttpRequest request = HttpUtil.createRequest(Method.valueOf(provider.getRepoListMethod()), baseUrl + provider.getRepoListUrl());
setCommonParams(platform, request, token);
query = StrUtil.blankToDefault(query, "");
String finalQuery = query;
provider.getRepoListParam().forEach((k, v) -> {
if ("${query}".equals(v)) {
v = v.replace("${query}", finalQuery);
}
if ("${page}".equals(v)) {
v = v.replace("${page}", String.valueOf(page.getPageNumber()));
}
if ("${pageSize}".equals(v)) {
v = v.replace("${pageSize}", String.valueOf(page.getPageSize()));
}
request.form(k, v);
});
String body;
int total;
request.getUrl();
log.debug(String.format("url: %s headers: %s form: %s", request.getUrl(), request.headers(), request.form()));
try (HttpResponse execute = request.execute()) {
body = execute.body();
int status = execute.getStatus();
Map<String, List<String>> headers = execute.headers();
String totalHeader = execute.header(provider.getRepoTotalHeader());
int totalCount = page.getPageSize() * page.getPageNumber();
if ("Link".equals(provider.getRepoTotalHeader()) && StrUtil.isNotBlank(totalHeader)) {
// github 特殊处理
Pattern pattern = Pattern.compile("page=(\\d+)&per_page=(\\d+)>; rel=\"last\"");
Matcher matcher = pattern.matcher(totalHeader);
if (matcher.find()) {
int linkPage = Integer.parseInt(matcher.group(2));
int linkPerPage = Integer.parseInt(matcher.group(1));
total = linkPage * linkPerPage;
} else {
total = totalCount;
}
} else {
total = StrUtil.isNotBlank(totalHeader) ? Integer.parseInt(totalHeader) : totalCount;
}
log.debug(String.format("status: %s body: %s headers: %s", status, body, headers));
Assert.state(execute.isOk(), String.format("请求失败: status: %s body: %s headers: %s", status, body, headers));
}
JSONArray jsonArray = JSONUtil.parse(body).getByPath(provider.getRepoListPath(), JSONArray.class);
List<JSONObject> data = jsonArray.stream().map(o -> {
JSONObject obj = (JSONObject) o;
JSONObject entries = new JSONObject();
provider.getRepoConvertPath().forEach((k, v) -> {
if (StrUtil.startWith(v, "$ ")) {
String[] expression = v.split(" ");
String value = obj.getStr(expression[1]);
// 对比方式
String compare = expression[2];
// 对比值
String compareValue = expression[3];
switch (compare) {
case "==":
entries.set(k, value.equals(compareValue));
break;
case "!=":
entries.set(k, !value.equals(compareValue));
break;
default:
throw new IllegalStateException("表达式目前仅支持 == 和 != 比较");
}
} else {
entries.set(k, obj.get(v));
}
});
entries.set("username", username);
return entries;
}).collect(Collectors.toList());
return JSONUtil.createObj().set("data", data).set("total", total);
}
public String getCurrentUserName(String platform, String token, String baseUrl) {
baseUrl = StrUtil.blankToDefault(baseUrl, getProviderConfig(platform).getBaseUrl());
Assert.state(StrUtil.isNotBlank(baseUrl), String.format("请填写 %s 的 地址", platform));
ImportRepoProviderConfig provider = getProviderConfig(platform);
HttpRequest request = HttpUtil.createRequest(Method.valueOf(provider.getCurrentUserMethod()), baseUrl + provider.getCurrentUserUrl());
setCommonParams(platform, request, token);
String body;
log.debug(String.format("url: %s headers: %s form: %s", request.getUrl(), request.headers(), request.form()));
try (HttpResponse execute = request.execute()) {
body = execute.body();
int status = execute.getStatus();
Map<String, List<String>> headers = execute.headers();
log.debug(String.format("status: %s body: %s headers: %s", status, body, headers));
Assert.state(execute.isOk(), String.format("请求失败: status: %s body: %s headers: %s", status, body, headers));
}
return JSONUtil.parse(body).getByPath(provider.getUserNamePath(), String.class);
}
}

View File

@ -0,0 +1,20 @@
baseUrl: https://try.gitea.io
authType: 1
authKey: Authorization
authValue: 'Bearer ${token}'
currentUserMethod: GET
currentUserUrl: /api/v1/user
userNamePath: login
repoListMethod: GET
repoListUrl: /api/v1/user/repos
repoListParam:
page: '${page}'
limit: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: full_name
description: description
url: clone_url
private: private
repoTotalHeader: X-Total-Count

View File

@ -0,0 +1,24 @@
baseUrl: https://gitee.com
authType: 2
authKey: access_token
authValue: '${token}'
currentUserMethod: GET
currentUserUrl: /api/v5/user
userNamePath: login
repoListMethod: GET
repoListUrl: /api/v5/user/repos
repoListParam:
type: all
sort: pushed
direction: desc
q: '${query}'
page: '${page}'
per_page: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: full_name
description: description
url: html_url
private: private
repoTotalHeader: total_count

View File

@ -0,0 +1,27 @@
baseUrl: https://api.github.com
authType: 1
authKey: Authorization
authValue: 'Bearer ${token}'
extraParams:
Accept: application/vnd.github.v3+json
X-GitHub-Api-Version: 2022-11-28
extraParamsType: 1
currentUserMethod: GET
currentUserUrl: /user
userNamePath: login
repoListMethod: GET
repoListUrl: /user/repos
repoListParam:
type: all
sort: pushed
direction: desc
page: '${page}'
per_page: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: full_name
description: description
url: clone_url
private: private
repoTotalHeader: Link

View File

@ -0,0 +1,23 @@
baseUrl: https://gitlab.com
authType: 1
authKey: Authorization
authValue: 'Bearer ${token}'
currentUserMethod: GET
currentUserUrl: /api/v4/user
userNamePath: username
repoListMethod: GET
repoListUrl: /api/v4/projects
repoListParam:
membership: true
order_by: updated_at
search: '${query}'
page: '${page}'
per_page: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: path_with_namespace
description: description
url: http_url_to_repo
private: $ visibility != public
repoTotalHeader: X-Total

View File

@ -0,0 +1,23 @@
baseUrl: https://gitlab.com
authType: 1
authKey: Authorization
authValue: 'Bearer ${token}'
currentUserMethod: GET
currentUserUrl: /api/v3/user
userNamePath: username
repoListMethod: GET
repoListUrl: /api/v3/projects
repoListParam:
membership: true
order_by: updated_at
search: '${query}'
page: '${page}'
per_page: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: path_with_namespace
description: description
url: http_url_to_repo
private: $ visibility != public
repoTotalHeader: X-Total

View File

@ -0,0 +1,20 @@
baseUrl: https://try.gogs.io
authType: 1
authKey: Authorization
authValue: 'Bearer ${token}'
currentUserMethod: GET
currentUserUrl: /api/v1/user
userNamePath: login
repoListMethod: GET
repoListUrl: /api/v1/user/repos
repoListParam:
page: '${page}'
limit: '${pageSize}'
repoListPath: ''
repoConvertPath:
name: name
full_name: full_name
description: description
url: clone_url
private: private
repoTotalHeader: X-Total-Count

View File

@ -92,6 +92,13 @@ export function authorizeRepos(param) {
});
}
export function providerInfo() {
return axios({
url: "/build/repository/provider_info",
method: "get",
});
}
export function sortItem(params) {
return axios({
url: "/build/repository/sort-item",

View File

@ -168,8 +168,8 @@
</template>
<a-form-model-item label="文件共享" prop="global">
<a-radio-group v-model="temp.global">
<a-radio :value="true"> 全局 </a-radio>
<a-radio :value="false"> 当前工作空间 </a-radio>
<a-radio :value="true"> 全局</a-radio>
<a-radio :value="false"> 当前工作空间</a-radio>
</a-radio-group>
</a-form-model-item>
<!-- <a-form-model-item v-if="temp.id" prop="restHideField">
@ -192,22 +192,18 @@
<a-form-model-item prop="token" label="私人令牌" help="使用私人令牌,可以在你不输入账号密码的情况下对你账号内的仓库进行管理,你可以在创建令牌时指定令牌所拥有的权限。">
<a-tooltip :title="`${giteeImportForm.type} 的令牌${importTypePlaceholder[giteeImportForm.type]}`">
<a-input v-model="giteeImportForm.token" :placeholder="importTypePlaceholder[giteeImportForm.type]">
<a-select slot="addonBefore" v-model="giteeImportForm.type">
<a-select-option value="gitee"> gitee </a-select-option>
<a-select-option value="github"> github </a-select-option>
<a-select-option value="gitlab"> gitlab </a-select-option>
<a-select-option value="gitea"> gitea </a-select-option>
<a-select-option value="gogs"> gogs </a-select-option>
<a-select slot="addonBefore" style="width: 100px" @change="importChange" v-model="giteeImportForm.type">
<a-select-option :value="item" v-for="item in Object.keys(providerData)" :key="item"> {{ item }}</a-select-option>
</a-select>
<a-button slot="addonAfter" size="small" type="primary" icon="search" @click="handleGiteeImportFormOk"> </a-button>
<a-button slot="addonAfter" size="small" type="primary" icon="search" @click="handleGiteeImportFormOk"></a-button>
</a-input>
</a-tooltip>
</a-form-model-item>
<a-form-model-item prop="address" label="地址" :help="importTypeAddressHelp[giteeImportForm.type]" v-if="importTypeAddressHelp[giteeImportForm.type]">
<a-form-model-item prop="address" label="地址">
<a-input v-model="giteeImportForm.address" placeholder="请填写平台地址" />
</a-form-model-item>
<a-form-model-item prop="condition" label="搜索" help="输入仓库名称或者仓库路径进行搜索">
<a-form-model-item prop="condition" label="搜索" help="输入仓库名称或者仓库路径进行搜索" v-if="providerData[giteeImportForm.type].query">
<a-input v-model="giteeImportForm.condition" placeholder="输入仓库名称或者仓库路径进行搜索" />
</a-form-model-item>
</a-form-model>
@ -236,7 +232,7 @@
</div>
</template>
<script>
import { authorizeRepos, deleteRepository, editRepository, getRepositoryList, restHideField, sortItem } from "@/api/repository";
import { providerInfo, authorizeRepos, deleteRepository, editRepository, getRepositoryList, restHideField, sortItem } from "@/api/repository";
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
export default {
@ -247,6 +243,13 @@ export default {
PAGE_DEFAULT_SIZW_OPTIONS: ["15", "20", "25", "30", "35", "40", "50"],
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY, { limit: 15 }),
list: [],
providerData: {
gitee: {
baseUrl: "https://gitee.com",
name: "gitee",
query: true
}
},
total: 0,
temp: {},
isSystem: false,
@ -263,7 +266,7 @@ export default {
width: 300,
sorter: true,
ellipsis: true,
scopedSlots: { customRender: "tooltip" },
scopedSlots: { customRender: "tooltip" }
},
{
title: "仓库类型",
@ -271,7 +274,7 @@ export default {
width: 100,
sorter: true,
ellipsis: true,
scopedSlots: { customRender: "repoType" },
scopedSlots: { customRender: "repoType" }
},
{
title: "协议",
@ -279,7 +282,7 @@ export default {
width: 100,
sorter: true,
ellipsis: true,
scopedSlots: { customRender: "protocol" },
scopedSlots: { customRender: "protocol" }
},
{ title: "共享", dataIndex: "workspaceId", ellipsis: true, scopedSlots: { customRender: "global" }, width: "80px" },
{ title: "创建人", dataIndex: "createUser", ellipsis: true, scopedSlots: { customRender: "tooltip" }, width: "120px" },
@ -289,14 +292,14 @@ export default {
dataIndex: "createTimeMillis",
sorter: true,
customRender: (text) => parseTime(text),
width: "170px",
width: "170px"
},
{
title: "修改时间",
dataIndex: "modifyTimeMillis",
sorter: true,
customRender: (text) => parseTime(text),
width: "170px",
width: "170px"
},
{
title: "操作",
@ -304,8 +307,8 @@ export default {
fixed: "right",
align: "center",
width: "180px",
scopedSlots: { customRender: "operation" },
},
scopedSlots: { customRender: "operation" }
}
],
reposColumns: [
{ title: "仓库名称", dataIndex: "name", ellipsis: true, scopedSlots: { customRender: "name" } },
@ -317,7 +320,7 @@ export default {
dataIndex: "description",
ellipsis: true,
scopedSlots: { customRender: "description" },
scopedSlots: { customRender: "description" }
},
{ title: "私有", dataIndex: "private", width: 80, ellipsis: true, scopedSlots: { customRender: "private" } },
{
@ -325,17 +328,17 @@ export default {
dataIndex: "operation",
width: 100,
scopedSlots: { customRender: "operation" },
align: "left",
},
align: "left"
}
],
giteeImportForm: Object.assign({}, PAGE_DEFAULT_LIST_QUERY, { limit: 15, type: "gitee" }),
giteeImportForm: Object.assign({}, PAGE_DEFAULT_LIST_QUERY, { limit: 15, type: "gitee", address: "https://gitee.com" }),
giteeImportFormRules: {
token: [{ required: true, message: "请输入私人令牌", trigger: "blur" }],
token: [{ required: true, message: "请输入私人令牌", trigger: "blur" }]
// address: [{ required: true, message: "", trigger: "blur" }],
},
rules: {
name: [{ required: true, message: "请填写仓库名称", trigger: "blur" }],
gitUrl: [{ required: true, message: "请填写仓库地址", trigger: "blur" }],
gitUrl: [{ required: true, message: "请填写仓库地址", trigger: "blur" }]
},
importTypePlaceholder: {
gitee: "在 设置-->安全设置-->私人令牌 中获取",
@ -343,13 +346,8 @@ export default {
gitlab: "在 preferences-->Access Tokens 中获取",
gitea: "在 设置 --> 应用 --> 生成令牌",
gogs: "在 设置 --> 应用 --> 生成令牌",
other: "请输入私人令牌",
},
importTypeAddressHelp: {
gitlab: "请输入 GitLab 的地址,支持自建 GitLab不需要输入协议gitlab.com、gitlab.jpom.io、10.1.2.3、10.1.2.3:8888 等",
gitea: "请输入 gitea 的地址不需要输入协议10.1.2.3、10.1.2.3:3000 等",
gogs: "请输入 gogs 的地址不需要输入协议10.1.2.3、10.1.2.3:3000 等",
},
other: "请输入私人令牌"
}
};
},
computed: {
@ -359,7 +357,7 @@ export default {
},
reposPagination() {
return COMPUTED_PAGINATION(this.giteeImportForm, this.PAGE_DEFAULT_SIZW_OPTIONS);
},
}
},
watch: {},
created() {
@ -367,7 +365,7 @@ export default {
},
methods: {
//
loadData(pointerEvent) {
async loadData(pointerEvent) {
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;
this.loading = true;
getRepositoryList(this.listQuery).then((res) => {
@ -377,6 +375,13 @@ export default {
}
this.loading = false;
});
const response = await providerInfo();
if (response.code === 200) {
this.providerData = response.data;
}
},
importChange(value) {
this.giteeImportForm.address = this.providerData[value].baseUrl;
},
// //
// handleFilter() {
@ -386,7 +391,7 @@ export default {
handleAdd() {
this.temp = {
repoType: 0,
protocol: 0,
protocol: 0
};
this.editVisible = true;
},
@ -420,12 +425,12 @@ export default {
userName: record.username,
password: this.giteeImportForm.token,
name: record.name,
gitUrl: record.url,
gitUrl: record.url
}).then((res) => {
if (res.code === 200) {
//
this.$notification.success({
message: res.msg,
message: res.msg
});
record.exists = true;
this.loadData();
@ -453,7 +458,7 @@ export default {
if (res.code === 200) {
//
this.$notification.success({
message: res.msg,
message: res.msg
});
this.editVisible = false;
this.loadData();
@ -471,19 +476,19 @@ export default {
cancelText: "取消",
onOk: () => {
const params = {
id: record.id,
id: record.id
//isRealDel: this.isSystem,
};
//
deleteRepository(params).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
message: res.msg
});
this.loadData();
}
});
},
}
});
},
@ -499,12 +504,12 @@ export default {
restHideField(record.id).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
message: res.msg
});
this.loadData();
}
});
},
}
});
},
//
@ -518,7 +523,7 @@ export default {
const msgData = {
top: "确定要将此数据置顶吗?",
up: "确定要将此数上移吗?",
down: "确定要将此数据下移吗?下移操作可能因为列表后续数据没有排序值操作无效!",
down: "确定要将此数据下移吗?下移操作可能因为列表后续数据没有排序值操作无效!"
};
let msg = msgData[method] || "确定要操作吗?";
if (!record.sortValue) {
@ -536,21 +541,21 @@ export default {
sortItem({
id: record.id,
method: method,
compareId: compareId,
compareId: compareId
}).then((res) => {
if (res.code == 200) {
this.$notification.success({
message: res.msg,
message: res.msg
});
this.loadData();
return false;
}
});
},
}
});
},
},
}
}
};
</script>
<style scoped>