ananke/.github/scripts/posterboy.mjs

163 lines
4.3 KiB
JavaScript
Raw Normal View History

import { readFile, writeFile, access, mkdir } from 'node:fs/promises';
import path from 'node:path';
import fs from 'node:fs';
import dotenv from 'dotenv';
import { homedir } from 'node:os';
const userHomeDir = homedir();
// Load .env files
const GLOBAL_ENV_PATH = path.join(userHomeDir, '.env');
const LOCAL_ENV_PATH = path.resolve('.env');
/**
* Load environment variables from a file if it exists.
* @param {string} filePath
* @returns {object} Parsed environment variables
*/
function loadEnvFile(filePath) {
if (fs.existsSync(filePath)) {
return dotenv.parse(fs.readFileSync(filePath));
}
return {};
}
// Merge global and local .env configurations
const globalEnv = loadEnvFile(GLOBAL_ENV_PATH);
const localEnv = loadEnvFile(LOCAL_ENV_PATH);
process.env = { ...globalEnv, ...process.env, ...localEnv };
// Configurable values
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK || '';
const GITHUB_DEV_TOKEN = process.env.GITHUB_DEV_TOKEN || '';
const GITHUB_REPO = process.env.GITHUB_REPO || 'theNewDynamic/gohugo-theme-ananke';
const DEFAULT_MESSAGE_TEMPLATE = 'New release: {{tag_name}} - {{html_url}}';
const MESSAGE_TEMPLATE = process.env.MESSAGE_TEMPLATE || DEFAULT_MESSAGE_TEMPLATE;
const CACHE_DIR = './cache';
const CACHE_FILE = 'github-releases.json';
const CACHE_FILE_PATH = path.join(CACHE_DIR, CACHE_FILE);
/**
* Ensures the cache directory exists, creating it if necessary.
* @returns {Promise<void>}
*/
async function ensureCacheDirectory() {
try {
await access(CACHE_DIR);
} catch {
try {
await mkdir(CACHE_DIR, { recursive: true });
} catch (err) {
console.error(`Failed to create cache directory: ${err.message}`);
process.exit(1);
}
}
}
/**
* Reads the cache file or returns an empty array if not found.
* @returns {Promise<string[]>}
*/
async function readCache() {
try {
const data = await readFile(CACHE_FILE_PATH, 'utf8');
return JSON.parse(data) || [];
} catch {
return [];
}
}
/**
* Writes data to the cache file.
* @param {string[]} data
*/
async function writeCache(data) {
await writeFile(CACHE_FILE_PATH, JSON.stringify(data, null, 2));
}
/**
* Fetches the latest release from the GitHub REST API.
* @returns {Promise<{ tag_name: string, html_url: string } | null>}
*/
async function fetchLatestRelease() {
try {
const response = await fetch('https://api.github.com/repos/' + GITHUB_REPO + '/releases', {
headers: {
Authorization: `token ${GITHUB_DEV_TOKEN}`,
},
});
if (!response.ok) {
throw new Error(`GitHub API request failed: ${response.statusText}`);
}
const releases = await response.json();
if (!Array.isArray(releases) || releases.length === 0) {
console.log('No releases found.');
return null;
}
return releases[0];
} catch (err) {
console.error('Failed to fetch releases:', err.message);
return null;
}
}
/**
* Posts a message to Discord using a webhook.
* @param {string} message
*/
async function postToDiscord(message) {
try {
const response = await fetch(DISCORD_WEBHOOK, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: message }),
});
if (!response.ok) {
throw new Error(`Failed to post to Discord: ${response.statusText}`);
}
console.log('Posted to Discord successfully.');
} catch (err) {
console.error('Failed to post to Discord:', err.message);
}
}
/**
* Formats the release message using the template.
* @param {Record<string, string>} releaseData
* @returns {string}
*/
function formatMessage(releaseData) {
return MESSAGE_TEMPLATE.replace(/{{\s*(\w+)\s*}}/g, (_, key) => releaseData[key] || '');
}
/**
* Main function to fetch the latest GitHub release and post it to Discord.
*/
async function main() {
try {
await ensureCacheDirectory();
const cachedIds = await readCache();
const latestRelease = await fetchLatestRelease();
if (latestRelease && !cachedIds.includes(latestRelease.tag_name)) {
const message = formatMessage(latestRelease);
await postToDiscord(message);
cachedIds.push(latestRelease.tag_name);
await writeCache(cachedIds);
} else {
console.log('No new releases to post.');
}
} catch (err) {
console.error('Error:', err.message);
}
}
main();