mirror of
https://git.eden-emu.dev/eden-emu/eden-bot
synced 2026-02-04 02:41:22 +01:00
watch releases and post them in the thread, pin message when create a thread
This commit is contained in:
1
data/pr_build_releases.json
Normal file
1
data/pr_build_releases.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -4,6 +4,7 @@ import { Client, GatewayIntentBits, Collection, Events } from 'discord.js';
|
||||
import parseLog from './functions/log_parser.js';
|
||||
import initializeReleaseWatcher from './functions/release_watcher.js';
|
||||
import initializeDescriptionWatcher from './functions/description_watcher.js';
|
||||
import initializePRBuildWatcher from './functions/pr_build_watcher.js';
|
||||
import { commands } from './functions/commands.js';
|
||||
|
||||
const { DISCORD_TOKEN } = process.env;
|
||||
@@ -32,6 +33,7 @@ client.once('ready', () => {
|
||||
// Release Watcher disabled for now, after the RAID have to setup again
|
||||
initializeReleaseWatcher(client);
|
||||
initializeDescriptionWatcher(client);
|
||||
initializePRBuildWatcher(client);
|
||||
});
|
||||
|
||||
client.on('messageCreate', parseLog);
|
||||
|
||||
152
src/functions/pr_build_watcher.js
Normal file
152
src/functions/pr_build_watcher.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import fetch from 'node-fetch';
|
||||
import { ChannelType, EmbedBuilder } from 'discord.js';
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
//forgot to store releases already posted, incase of a restart don't report
|
||||
const TRACKED_RELEASES_FILE = join(__dirname, '../../data/pr_build_releases.json');
|
||||
|
||||
const {
|
||||
CHANNEL_ID,
|
||||
GITHUB_REPO: REPO = 'Eden-CI/PR',
|
||||
GITHUB_TOKEN,
|
||||
POLL_INTERVAL_MS,
|
||||
} = process.env;
|
||||
|
||||
const POLL_INTERVAL = parseInt(POLL_INTERVAL_MS) || 10 * 60 * 1000;
|
||||
let isCheckingReleases = false;
|
||||
let lastCheckedReleaseIds = new Set();
|
||||
|
||||
// Load tracked releases from file
|
||||
function loadTrackedReleases() {
|
||||
try {
|
||||
if (existsSync(TRACKED_RELEASES_FILE)) {
|
||||
const data = readFileSync(TRACKED_RELEASES_FILE, 'utf-8');
|
||||
const ids = JSON.parse(data);
|
||||
return new Set(ids);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[PR Build Watcher] Error loading tracked releases:', e);
|
||||
}
|
||||
return new Set();
|
||||
}
|
||||
|
||||
function saveTrackedReleases(releaseIds) {
|
||||
try {
|
||||
const dataDir = dirname(TRACKED_RELEASES_FILE);
|
||||
if (!existsSync(dataDir)) {
|
||||
mkdirSync(dataDir, { recursive: true });
|
||||
}
|
||||
const data = JSON.stringify(Array.from(releaseIds), null, 2);
|
||||
writeFileSync(TRACKED_RELEASES_FILE, data, 'utf-8');
|
||||
} catch (e) {
|
||||
console.error('[PR Build Watcher] Error saving tracked releases:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize from file
|
||||
lastCheckedReleaseIds = loadTrackedReleases();
|
||||
|
||||
function disabled() {
|
||||
console.log('[PR Build Watcher] Service is disabled due to missing environment variables.');
|
||||
console.log('[PR Build Watcher][DEBUG] CHANNEL_ID = ' + CHANNEL_ID + ' GITHUB_TOKEN = ' + GITHUB_TOKEN);
|
||||
}
|
||||
|
||||
async function postReleaseToThread(release, channel, prNumber) {
|
||||
try {
|
||||
// Find thread with the name "Build {PRNMBER}"
|
||||
const threadName = `Build ${prNumber}`;
|
||||
|
||||
const activeThreads = await channel.threads.fetchActive();
|
||||
const archivedThreads = await channel.threads.fetchArchived({ limit: 100 });
|
||||
|
||||
let targetThread = activeThreads.threads.find(t => t.name === threadName);
|
||||
if (!targetThread) {
|
||||
targetThread = archivedThreads.threads.find(t => t.name === threadName);
|
||||
}
|
||||
|
||||
if (!targetThread) {
|
||||
console.log(`[PR Build Watcher] Thread "${threadName}" not found, skipping release ${release.tag_name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetThread.locked || targetThread.archived) {
|
||||
console.log(`[PR Build Watcher] Thread "${threadName}" is ${targetThread.locked ? 'locked' : 'archived'}, skipping release ${release.tag_name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0x00FF00)
|
||||
.setTitle(`New Build for PR ${prNumber}`)
|
||||
.setDescription(`A new build for PR ${prNumber} has been uploaded!`)
|
||||
.addFields(
|
||||
{ name: 'Release Name', value: release.name || release.tag_name, inline: false },
|
||||
{ name: 'Link', value: `[View Release](${release.html_url})`, inline: false }
|
||||
)
|
||||
.setTimestamp(new Date(release.published_at))
|
||||
.setFooter({ text: 'Eden CI Release' });
|
||||
|
||||
await targetThread.send({ embeds: [embed] });
|
||||
console.log(`[PR Build Watcher] Posted release ${release.tag_name} to thread "${threadName}"`);
|
||||
} catch (e) {
|
||||
console.error(`[PR Build Watcher] Error posting release ${release.tag_name} to thread:`, e);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkPRBuilds(client) {
|
||||
if (isCheckingReleases) {
|
||||
console.log('[PR Build Watcher] Skipping check: a check is already in progress.');
|
||||
return;
|
||||
}
|
||||
isCheckingReleases = true;
|
||||
try {
|
||||
const res = await fetch(`https://api.github.com/repos/${REPO}/releases`, {
|
||||
headers: { 'User-Agent': 'release-watcher, EDEN', 'Authorization': `token ${GITHUB_TOKEN}` }
|
||||
});
|
||||
|
||||
if (res.status === 403) {
|
||||
console.error('[PR Build Watcher] GitHub API error: Rate limit or access denied.');
|
||||
return;
|
||||
}
|
||||
if (!res.ok) throw new Error(`GitHub API responded with status ${res.status}`);
|
||||
|
||||
const allReleases = await res.json();
|
||||
if (!Array.isArray(allReleases)) return;
|
||||
|
||||
const channel = await client.channels.fetch(CHANNEL_ID);
|
||||
if (channel.type !== ChannelType.GuildForum) {
|
||||
console.error(`[PR Build Watcher] Channel ${CHANNEL_ID} is not a Forum Channel.`);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const release of allReleases) {
|
||||
if (lastCheckedReleaseIds.has(release.id)) continue;
|
||||
const prNumber = release.tag_name.split('-')[0];
|
||||
await postReleaseToThread(release, channel, prNumber);
|
||||
lastCheckedReleaseIds.add(release.id);
|
||||
}
|
||||
if (lastCheckedReleaseIds.size > 100) {
|
||||
const idsArray = Array.from(lastCheckedReleaseIds);
|
||||
lastCheckedReleaseIds = new Set(idsArray.slice(-100));
|
||||
}
|
||||
saveTrackedReleases(lastCheckedReleaseIds);
|
||||
} catch (e) {
|
||||
console.error('[PR Build Watcher] Error in checkPRBuilds:', e);
|
||||
} finally {
|
||||
isCheckingReleases = false;
|
||||
}
|
||||
}
|
||||
|
||||
function initializePRBuildWatcher(client) {
|
||||
console.log(`[PR Build Watcher] Service initialized. Watching ${REPO} every ${POLL_INTERVAL / 1000} seconds.`);
|
||||
console.log(`[PR Build Watcher] Loaded ${lastCheckedReleaseIds.size} previously tracked releases.`);
|
||||
checkPRBuilds(client);
|
||||
setInterval(() => checkPRBuilds(client), POLL_INTERVAL);
|
||||
}
|
||||
|
||||
const isEnabled = CHANNEL_ID && GITHUB_TOKEN;
|
||||
const moduleToExport = isEnabled ? initializePRBuildWatcher : disabled;
|
||||
|
||||
export default moduleToExport;
|
||||
@@ -35,13 +35,21 @@ async function announceRelease(release, channel, baseTag) {
|
||||
let content = `**${title} - ${release.name}**\n\n${desc}\n\n🔗 [Go to pull request](${prUrl})\n\n📝 [Go to downloads](${release.html_url})`;
|
||||
if (content.length > 2000) content = content.slice(0, 1997) + '...';
|
||||
|
||||
await channel.threads.create({
|
||||
const thread = await channel.threads.create({
|
||||
name: title,
|
||||
autoArchiveDuration: 10080,
|
||||
message: { content, flags: MessageFlags.SuppressEmbeds },
|
||||
appliedTags: ['1396925576765374655'] // Tag ID for "Needs Testing" in builds forum.
|
||||
});
|
||||
|
||||
// Pin the starter message
|
||||
const starterMessage = await thread.fetchStarterMessage();
|
||||
if (starterMessage) {
|
||||
await starterMessage.pin();
|
||||
console.log(`[Release Watcher] Created and pinned thread for ${title}`);
|
||||
} else {
|
||||
console.log(`[Release Watcher] Created thread for ${title}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[Release Watcher] Error announcing release ${release.tag_name}:`, e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user