diff --git a/config/example.index.js b/config/example.index.js index 3e8e0b3..001ca03 100644 --- a/config/example.index.js +++ b/config/example.index.js @@ -36,6 +36,14 @@ module.exports = { i18n: { baseLanguage: "en", }, + orizuru: { + serverName: "Orizuru", + }, + web_from_git: { + gitRepo: "", + gitSecret: "", + gitUser: "", + }, //$StripEnd }, }; \ No newline at end of file diff --git a/src/config/modules/index.ts b/src/config/modules/index.ts index f3d9199..09bddfb 100644 --- a/src/config/modules/index.ts +++ b/src/config/modules/index.ts @@ -2,6 +2,8 @@ import { Parseable, ValidateProperty } from "parzival"; import DiscordConfig from "./discord"; //$StripStart import I18nConfig from "./i18n"; +import OrizuruConfig from "./orizuru"; +import WebFromGitConfig from "./web_from_git"; //$StripEnd @Parseable() @@ -20,5 +22,19 @@ export default class ModuleConfigs { className: "I18nConfig", }) i18n!: I18nConfig; + + @ValidateProperty({ + type: "object", + recurse: true, + className: "OrizuruConfig", + }) + orizuru!: OrizuruConfig; + + @ValidateProperty({ + type: "object", + recurse: true, + className: "WebFromGitConfig", + }) + web_from_git!: WebFromGitConfig; //$StripEnd } \ No newline at end of file diff --git a/src/config/modules/orizuru.ts b/src/config/modules/orizuru.ts new file mode 100644 index 0000000..0bf861a --- /dev/null +++ b/src/config/modules/orizuru.ts @@ -0,0 +1,10 @@ +import { Parseable, ValidateProperty } from "parzival"; + +@Parseable() +export default class OrizuruConfig { + @ValidateProperty({ + type: "string", + optional: true + }) + serverName?: string; +} \ No newline at end of file diff --git a/src/config/modules/web_from_git.ts b/src/config/modules/web_from_git.ts new file mode 100644 index 0000000..5cb83f3 --- /dev/null +++ b/src/config/modules/web_from_git.ts @@ -0,0 +1,19 @@ +import { Parseable, ValidateProperty } from "parzival"; + +@Parseable() +export default class WebFromGitConfig { + @ValidateProperty({ + type: "string", + }) + gitUser!: string; + + @ValidateProperty({ + type: "string", + }) + gitSecret!: string; + + @ValidateProperty({ + type: "string", + }) + gitRepo!: string; +} \ No newline at end of file diff --git a/src/modules/orizuru/index.ts b/src/modules/orizuru/index.ts new file mode 100644 index 0000000..57c5cdd --- /dev/null +++ b/src/modules/orizuru/index.ts @@ -0,0 +1,16 @@ +import Module from "@src/engine/modules"; +import { debug } from "@src/engine/utils/Logger"; +import { Orizuru } from "@garycraft/orizuru"; +import { getAppContext } from "@src/engine/utils/Composable"; + + +export default { + name: "orizuru", + loadFunction: async (config) => { + return new Orizuru(getAppContext()) + }, + initFunction: async (ctx, config) => { + getAppContext().http.server.post("/orizuru", ctx.getExpressHandler()) + debug("Orizuru module initialized") + } +} satisfies Module; \ No newline at end of file diff --git a/src/modules/web_from_git/index.ts b/src/modules/web_from_git/index.ts new file mode 100644 index 0000000..798798c --- /dev/null +++ b/src/modules/web_from_git/index.ts @@ -0,0 +1,16 @@ +import Module from "@src/engine/modules"; +import EventEmitter from "events"; + + +export default { + name: "web_from_git", + paths: { + tasks: "tasks", + }, + loadFunction: async (config) => { + return new EventEmitter(); + }, + initFunction: async (ctx, config) => { + + } +} satisfies Module; \ No newline at end of file diff --git a/src/modules/web_from_git/tasks/pullSite.ts b/src/modules/web_from_git/tasks/pullSite.ts new file mode 100644 index 0000000..73409b3 --- /dev/null +++ b/src/modules/web_from_git/tasks/pullSite.ts @@ -0,0 +1,104 @@ +import { simpleGit, SimpleGitOptions, CheckRepoActions } from 'simple-git'; +import { ScheduledTask } from "@src/engine/types/Executors"; +import { debug, error, info } from "@src/engine/utils/Logger"; +import path from "path"; +import { getTempPath, getWebPublicDir } from "@src/engine/utils/Runtime"; +import fs from "fs"; +import { spawnChild } from "@src/engine/utils/Process"; +import ExtendedClient from "@src/modules/discord/extendedclient"; +import { getConfigProperty } from '@src/engine/utils/Configuration'; +import WebFromGitConfig from '@src/config/modules/web_from_git'; + +const WebStorageBasePath = path.join(getTempPath(), "webpage"); + +const GITOPTIONS: Partial = { + baseDir: WebStorageBasePath, + binary: 'git', + maxConcurrentProcesses: 6, + trimmed: false, +}; + +export default { + name: "BuildWebsite", + cronInterval: "* * * * *", + async task(app) { + const cfg = getConfigProperty("modules.web_from_git"); + if (!cfg) { + error("No config found for web_from_git"); + return; + } + /* if (app.config.node_env !== "production") { + debug("Not building site in development mode"); + return; + } */ + debug("Checking repo for changes"); + // does directory exist? + if (!fs.existsSync(WebStorageBasePath)) { + debug("Creating web storage directory", WebStorageBasePath); + fs.mkdirSync(WebStorageBasePath, { recursive: true }); + } + const repoUrl = `https://${cfg.gitUser}:${cfg.gitSecret}@${cfg.gitRepo}` + const git = simpleGit(GITOPTIONS); + try { + debug(WebStorageBasePath) + // is there a repo? + const exists = await git.checkIsRepo(CheckRepoActions.IS_REPO_ROOT); + if (!exists) { + debug("Cloning repo", cfg.gitRepo, "to", WebStorageBasePath); + await git.clone(repoUrl, WebStorageBasePath); + } + // are there remote changes? + await git.fetch(); + const status = await git.status(); + const hasIndexHtml = fs.existsSync(path.join(getWebPublicDir(), "index.html")); + if (status.behind > 0) { + // pull the changes + await git.pull(); + } + else if (!hasIndexHtml) { + debug("No index.html found, not skipping build"); + } + else { + debug("No changes in the repo, skipping build"); + return; + } + } + catch (e) { + error("Error checking repo for changes!", e); + } + + app.events.emit("modules:discord:siteBuildStarted") + info("Repo checked for changes, building site!"); + // build the site, expecting to use npm run build + let buildError = false; + try { + const npmVersion = await spawnChild("npm -v"); + const nodeVersion = await spawnChild("node -v"); + debug("Node version", nodeVersion.stdout); + debug("NPM version", npmVersion.stdout); + + // dependencies + const installed = await spawnChild("npm install", { + cwd: WebStorageBasePath, + }); + debug("Dependencies installed!", installed.stdout, installed.stderr); + // build + const built = await spawnChild("npm run build", { + cwd: WebStorageBasePath, + }); + debug("Build Result", built.stdout, built.stderr); + + } catch (e) { + error("Error building site!", e); + buildError = true; + } + if (buildError) { + error("Site build failed!"); + return; + } + debug("Site built!"); + app.events.emit("modules:discord:siteBuildCompleted") + + info("Done!") + }, +} satisfies ScheduledTask; \ No newline at end of file