GiteaRepoManager/index.html
2025-05-16 16:17:31 +08:00

268 lines
7.0 KiB
HTML

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<title>手動輸入組織,批次建立 Gitea 儲存庫與團隊</title>
<style>
body {
font-family: sans-serif;
}
#log {
white-space: pre-wrap;
background: #f0f0f0;
padding: 1em;
border-radius: 8px;
height: 400px;
overflow-y: auto;
margin-top: 1em;
}
label,
input {
font-size: 1rem;
}
input {
margin-left: 0.5em;
}
button {
margin-left: 1em;
}
</style>
</head>
<body>
<h2>
輸入組織名稱並從 JSON 建立儲存庫+設定團隊
<br />
PS.請先建好團隊(或使用下方按鈕批次建立)
</h2>
<label for="orgInput">組織名稱:</label>
<input type="text" id="orgInput" placeholder="請輸入組織名稱" />
<button onclick="loadAndCreateTeams()">創建團隊</button>
<button onclick="loadAndCreateRepos()">開始建立儲存庫</button>
<div id="log"></div>
<script>
const accessToken = "587f612b5cdbf59bfa6ebb8e082109a6aa26d435";
// https://dash.cloudflare.com/361c3fb1feb10c54c262c3872c51a3a5/workers/services/view/cors-anywhere/production/metrics
const proxy = "https://cors-anywhere.bir840124.workers.dev/?url=";
const giteaAPIBase = "https://git.catan.com.tw/api/v1";
const logBox = document.getElementById("log");
function log(message) {
logBox.textContent += message + "\n";
logBox.scrollTop = logBox.scrollHeight;
}
// 建立儲存庫功能(維持不變)
async function loadAndCreateRepos() {
logBox.textContent = ""; // 清空 log
const orgInput = document.getElementById("orgInput").value.trim();
if (!orgInput) {
alert("請輸入組織名稱");
return;
}
log(`✅ 開始建立儲存庫:${orgInput}`);
try {
const res = await fetch("repos.json");
const repoList = await res.json();
for (const repo of repoList) {
repo.org = orgInput;
await createRepoWithSettings(repo);
}
log("✅ 所有儲存庫處理完成!");
} catch (err) {
log("❌ 讀取 repos.json 失敗:" + err.message);
}
}
async function repoExists(org, repoName) {
const url = `${giteaAPIBase}/orgs/${org}/repos`;
const res = await fetch(proxy + url, {
headers: { "Authorization": `token ${accessToken}` }
});
if (!res.ok) {
throw new Error(`查詢儲存庫失敗,狀態碼:${res.status}`);
}
const repos = await res.json();
return repos.some(r => r.name === repoName);
}
async function createRepoWithSettings(repo) {
if (await repoExists(repo.org, repo.name)) {
log(`⚠️ 儲存庫已存在,略過建立:${repo.org}/${repo.name}`);
return;
}
const createUrl = `${giteaAPIBase}/orgs/${repo.org}/repos`;
const payload = {
name: repo.name,
description: repo.description || "",
default_branch: repo.default_branch || "master",
private: false,
auto_init: true
};
try {
const response = await fetch(proxy + createUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `token ${accessToken}`
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (response.ok) {
log(`✅ 建立儲存庫:${repo.org}/${repo.name}`);
if (repo.teams?.length > 0) {
for (const team of repo.teams) {
await addTeamToRepo(repo.org, repo.name, team);
}
}
} else {
log(`⚠️ 建立失敗:${repo.org}/${repo.name} - ${data.message}`);
}
} catch (err) {
log(`❌ 建立錯誤:${repo.org}/${repo.name} - ${err.message}`);
}
}
async function addTeamToRepo(org, repo, teamName) {
const teamsURL = `${giteaAPIBase}/orgs/${org}/teams`;
const teamRes = await fetch(proxy + teamsURL, {
headers: { "Authorization": `token ${accessToken}` }
});
const teams = await teamRes.json();
const targetTeam = teams.find(t => t.name === teamName);
if (!targetTeam) {
log(`⚠️ 找不到團隊:${teamName}`);
return;
}
const url = `${giteaAPIBase}/teams/${targetTeam.id}/repos/${org}/${repo}`;
const res = await fetch(proxy + url, {
method: "PUT",
headers: { "Authorization": `token ${accessToken}` }
});
if (res.ok) {
log(`👥 加入團隊:${teamName}`);
} else {
log(`⚠️ 加團隊失敗:${teamName}`);
}
}
// 新增:創建團隊功能
async function loadAndCreateTeams() {
logBox.textContent = ""; // 清空 log
const orgInput = document.getElementById("orgInput").value.trim();
if (!orgInput) {
alert("請輸入組織名稱");
return;
}
log(`✅ 開始建立團隊:${orgInput}`);
try {
// 載入 teams.json
const res = await fetch("teams.json");
const teamList = await res.json();
for (const team of teamList) {
await createTeam(orgInput, team);
}
log("✅ 所有團隊建立完成!");
} catch (err) {
log("❌ 讀取 teams.json 失敗:" + err.message);
}
}
async function createTeam(org, team) {
const url = `${giteaAPIBase}/orgs/${org}/teams`;
const payload = {
name: team.name,
description: team.description || "",
permission: "none",
units: team.units || [],
units_map: team.units_map || {},
can_create_org_repo: false,
includes_all_repositories: false
};
try {
const response = await fetch(proxy + url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `token ${accessToken}`
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (response.ok) {
log(`✅ 團隊建立成功:${team.name}`);
if (team.members?.length > 0) {
for (const username of team.members) {
await addMemberToTeam(data.id, username);
}
}
} else if (data.message?.includes("team already exists")) {
log(`⚠️ 團隊已存在,略過:${team.name}`);
} else {
log(`⚠️ 建立團隊失敗:${team.name} - ${data.message}`);
}
} catch (err) {
log(`❌ 團隊建立錯誤:${team.name} - ${err.message}`);
}
// await delay(1000); // 每次請求間隔 1 秒,避免 rate limit
}
async function addMemberToTeam(teamId, username) {
const url = `${giteaAPIBase}/teams/${teamId}/members/${username}`;
try {
const res = await fetch(proxy + url, {
method: "PUT",
headers: { "Authorization": `token ${accessToken}` }
});
if (res.ok) {
log(`👤 新增成員:${username}`);
} else {
const data = await res.json();
log(`⚠️ 新增成員失敗:${username} - ${data.message || res.statusText}`);
}
} catch (err) {
log(`❌ 新增成員錯誤:${username} - ${err.message}`);
}
// await delay(500);
}
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
</script>
</body>
</html>