296 lines
7.6 KiB
HTML
296 lines
7.6 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: 100%;
|
||
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 = "96ed6b6d33931b122c7f12f94153594be0d75b32";
|
||
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 = "";
|
||
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);
|
||
}
|
||
}
|
||
|
||
// 新增:建立 Issue
|
||
if (repo.issue) {
|
||
await createIssue(repo.org, repo.name, repo.issue);
|
||
}
|
||
|
||
} else {
|
||
log(`⚠️ 建立失敗:${repo.org}/${repo.name} - ${data.message}`);
|
||
}
|
||
|
||
} catch (err) {
|
||
log(`❌ 建立錯誤:${repo.org}/${repo.name} - ${err.message}`);
|
||
}
|
||
}
|
||
|
||
async function createIssue(org, repoName, issue) {
|
||
const url = `${giteaAPIBase}/repos/${org}/${repoName}/issues`;
|
||
const payload = {
|
||
title: issue.title || "",
|
||
body: issue.content || ""
|
||
};
|
||
|
||
try {
|
||
const res = await fetch(proxy + url, {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": `token ${accessToken}`
|
||
},
|
||
body: JSON.stringify(payload)
|
||
});
|
||
|
||
if (res.ok) {
|
||
log(`📌 已建立 Issue:${issue.title}`);
|
||
} else {
|
||
const data = await res.json();
|
||
log(`⚠️ 建立 Issue 失敗:${data.message || res.statusText}`);
|
||
}
|
||
} catch (err) {
|
||
log(`❌ 建立 Issue 錯誤:${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 = "";
|
||
const orgInput = document.getElementById("orgInput").value.trim();
|
||
if (!orgInput) {
|
||
alert("請輸入組織名稱");
|
||
return;
|
||
}
|
||
log(`✅ 開始建立團隊:${orgInput}`);
|
||
|
||
try {
|
||
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}`);
|
||
}
|
||
}
|
||
|
||
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}`);
|
||
}
|
||
}
|
||
|
||
async function delay(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |