gitea plugin now imports releases as changelog entries
This commit is contained in:
@@ -49,6 +49,7 @@ async function fetchPublicRepos(url, user, token) {
|
|||||||
if (!repo.private && !repo.fork) {
|
if (!repo.private && !repo.fork) {
|
||||||
repos.push({
|
repos.push({
|
||||||
name: repo.name,
|
name: repo.name,
|
||||||
|
fullName: repo.full_name,
|
||||||
description: repo.description || null,
|
description: repo.description || null,
|
||||||
htmlUrl: repo.html_url,
|
htmlUrl: repo.html_url,
|
||||||
updatedAt: repo.updated_at,
|
updatedAt: repo.updated_at,
|
||||||
@@ -63,6 +64,29 @@ async function fetchPublicRepos(url, user, token) {
|
|||||||
return repos;
|
return repos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchReleases(url, repoFullName, token) {
|
||||||
|
const headers = {};
|
||||||
|
if (token) headers["Authorization"] = `token ${token}`;
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${url}/api/v1/repos/${repoFullName}/releases?limit=50`,
|
||||||
|
{ headers }
|
||||||
|
);
|
||||||
|
if (!res.ok) return [];
|
||||||
|
|
||||||
|
const releases = await res.json();
|
||||||
|
return (releases || [])
|
||||||
|
.filter((r) => !r.draft)
|
||||||
|
.map((r) => ({
|
||||||
|
id: r.id,
|
||||||
|
tag: r.tag_name,
|
||||||
|
name: r.name || r.tag_name,
|
||||||
|
body: r.body || "",
|
||||||
|
publishedAt: r.published_at || r.created_at,
|
||||||
|
htmlUrl: r.html_url,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function parseProfileUrl(raw) {
|
function parseProfileUrl(raw) {
|
||||||
const clean = String(raw).replace(/\/+$/, "");
|
const clean = String(raw).replace(/\/+$/, "");
|
||||||
const parts = clean.split("/");
|
const parts = clean.split("/");
|
||||||
@@ -84,18 +108,24 @@ async function syncRepos(ctx) {
|
|||||||
return { synced: 0, error: "invalid profile URL - expected https://instance/username" };
|
return { synced: 0, error: "invalid profile URL - expected https://instance/username" };
|
||||||
}
|
}
|
||||||
|
|
||||||
const repos = await fetchPublicRepos(url, user, token ? String(token) : null);
|
const tkn = token ? String(token) : null;
|
||||||
|
const repos = await fetchPublicRepos(url, user, tkn);
|
||||||
let created = 0;
|
let created = 0;
|
||||||
let updated = 0;
|
let updated = 0;
|
||||||
|
let changelogsCreated = 0;
|
||||||
|
|
||||||
|
// track which releases we've already imported
|
||||||
|
const importedReleases = await ctx.store.get("importedReleases");
|
||||||
|
const imported = new Set(Array.isArray(importedReleases) ? importedReleases : []);
|
||||||
|
|
||||||
for (const repo of repos) {
|
for (const repo of repos) {
|
||||||
const slug = repo.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
const slug = repo.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
||||||
const existing = await ctx.prisma.board.findUnique({ where: { slug } });
|
let board = await ctx.prisma.board.findUnique({ where: { slug } });
|
||||||
|
|
||||||
if (existing) {
|
if (board) {
|
||||||
await ctx.prisma.board.update({
|
await ctx.prisma.board.update({
|
||||||
where: { slug },
|
where: { slug },
|
||||||
data: { externalUrl: repo.htmlUrl, description: repo.description || existing.description },
|
data: { externalUrl: repo.htmlUrl, description: repo.description || board.description },
|
||||||
});
|
});
|
||||||
updated++;
|
updated++;
|
||||||
} else {
|
} else {
|
||||||
@@ -103,7 +133,7 @@ async function syncRepos(ctx) {
|
|||||||
const iconName = pickRandom(ICONS, repo.name);
|
const iconName = pickRandom(ICONS, repo.name);
|
||||||
const iconColor = pickRandom(COLORS, repo.name + "color");
|
const iconColor = pickRandom(COLORS, repo.name + "color");
|
||||||
|
|
||||||
await ctx.prisma.board.create({
|
board = await ctx.prisma.board.create({
|
||||||
data: {
|
data: {
|
||||||
slug,
|
slug,
|
||||||
name,
|
name,
|
||||||
@@ -115,14 +145,38 @@ async function syncRepos(ctx) {
|
|||||||
});
|
});
|
||||||
created++;
|
created++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetch releases and create changelog entries
|
||||||
|
const releases = await fetchReleases(url, repo.fullName, tkn);
|
||||||
|
for (const release of releases) {
|
||||||
|
const releaseKey = `${repo.fullName}:${release.id}`;
|
||||||
|
if (imported.has(releaseKey)) continue;
|
||||||
|
|
||||||
|
const body = release.body
|
||||||
|
? `${release.body}\n\n[View release](${release.htmlUrl})`
|
||||||
|
: `[View release](${release.htmlUrl})`;
|
||||||
|
|
||||||
|
await ctx.prisma.changelogEntry.create({
|
||||||
|
data: {
|
||||||
|
title: `${titleCase(repo.name)} ${release.name}`,
|
||||||
|
body,
|
||||||
|
boardId: board.id,
|
||||||
|
publishedAt: new Date(release.publishedAt),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
imported.add(releaseKey);
|
||||||
|
changelogsCreated++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await ctx.store.set("importedReleases", [...imported]);
|
||||||
const lastSync = new Date().toISOString();
|
const lastSync = new Date().toISOString();
|
||||||
await ctx.store.set("lastSync", lastSync);
|
await ctx.store.set("lastSync", lastSync);
|
||||||
await ctx.store.set("repoCount", repos.length);
|
await ctx.store.set("repoCount", repos.length);
|
||||||
ctx.logger.info({ created, updated, total: repos.length }, "gitea-sync completed");
|
ctx.logger.info({ created, updated, changelogsCreated, total: repos.length }, "gitea-sync completed");
|
||||||
|
|
||||||
return { synced: repos.length, created, updated };
|
return { synced: repos.length, created, updated, changelogsCreated };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
Reference in New Issue
Block a user