generated from nhcarrigan/template
feat: initial prototype
All checks were successful
Node.js CI / Lint and Test (push) Successful in 31s
All checks were successful
Node.js CI / Lint and Test (push) Successful in 31s
This commit is contained in:
parent
2ba0ae631b
commit
f3ab9e541f
38
.gitea/workflows/ci.yml
Normal file
38
.gitea/workflows/ci.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: Node.js CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint and Test
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Source Files
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Use Node.js v22
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 10
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Lint Source Files
|
||||||
|
run: pnpm run lint
|
||||||
|
|
||||||
|
- name: Verify Build
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: pnpm run test
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
prod
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
},
|
||||||
|
"eslint.validate": ["typescript"]
|
||||||
|
}
|
5
eslint.config.js
Normal file
5
eslint.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import NaomisConfig from "@nhcarrigan/eslint-config";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...NaomisConfig
|
||||||
|
]
|
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "standup-bot",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Discord bot to post standup reminders for the Commit Your Code cohort.",
|
||||||
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf prod && tsc",
|
||||||
|
"lint": "eslint src --max-warnings 0",
|
||||||
|
"start": "op run --env-file=prod.env --no-masking -- node prod/index.js",
|
||||||
|
"test": "echo \"No tests yet!\" && exit 0"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Naomi Carrigan",
|
||||||
|
"license": "See license in LICENSE.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@nhcarrigan/eslint-config": "5.1.0",
|
||||||
|
"@nhcarrigan/typescript-config": "4.0.0",
|
||||||
|
"@types/node": "22.13.1",
|
||||||
|
"@types/node-schedule": "2.1.7",
|
||||||
|
"@vitest/coverage-istanbul": "3.0.5",
|
||||||
|
"eslint": "9.20.0",
|
||||||
|
"typescript": "5.7.3",
|
||||||
|
"vitest": "3.0.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nhcarrigan/logger": "1.0.0",
|
||||||
|
"discord.js": "14.18.0",
|
||||||
|
"node-schedule": "2.1.1"
|
||||||
|
}
|
||||||
|
}
|
4764
pnpm-lock.yaml
generated
Normal file
4764
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
prod.env
Normal file
2
prod.env
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
DISCORD_TOKEN="op://Environment Variables - Naomi/Standup Bot/discord_token"
|
||||||
|
LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth"
|
24
src/config/channels.ts
Normal file
24
src/config/channels.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The channels to post standup reminders in.
|
||||||
|
*/
|
||||||
|
export const channels = [
|
||||||
|
"1326291362483671202",
|
||||||
|
"1329625299406684263",
|
||||||
|
"1326291172896931921",
|
||||||
|
"1326291132535013409",
|
||||||
|
"1326291241045856286",
|
||||||
|
"1326291186863833169",
|
||||||
|
"1326291226332496026",
|
||||||
|
"1326291379621597304",
|
||||||
|
"1326291254421749770",
|
||||||
|
"1326291160632655983",
|
||||||
|
"1326291146267430912",
|
||||||
|
"1326291198666866788",
|
||||||
|
"1326291214026408009",
|
||||||
|
];
|
38
src/index.ts
Normal file
38
src/index.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
import { Client, Events, GatewayIntentBits } from "discord.js";
|
||||||
|
import { scheduleJob } from "node-schedule";
|
||||||
|
import { standup } from "./modules/standup.js";
|
||||||
|
import { logger } from "./utils/logger.js";
|
||||||
|
|
||||||
|
process.on("unhandledRejection", (error) => {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
void logger.error("Unhandled Rejection", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void logger.error("unhandled rejection", new Error(String(error)));
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("uncaughtException", (error) => {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
void logger.error("Uncaught Exception", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void logger.error("uncaught exception", new Error(String(error)));
|
||||||
|
});
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
intents: [ GatewayIntentBits.Guilds ],
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on(Events.ClientReady, () => {
|
||||||
|
void logger.log("debug", "Bot is ready.");
|
||||||
|
scheduleJob("reminders", "0 6 * * 1-5", async() => {
|
||||||
|
await standup(client);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.login(process.env.DISCORD_TOKEN);
|
48
src/modules/standup.ts
Normal file
48
src/modules/standup.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
import { channels } from "../config/channels.js";
|
||||||
|
import { logger } from "../utils/logger.js";
|
||||||
|
import type { Client } from "discord.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts a daily standup reminder in configured channels.
|
||||||
|
* @param client - The Discord client.
|
||||||
|
*/
|
||||||
|
export const standup = async(client: Client): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const mapped = await Promise.all(
|
||||||
|
channels.map(async(channel) => {
|
||||||
|
const fetched = await client.channels.fetch(channel).catch(() => {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!fetched) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!fetched.isTextBased() || !("send" in fetched)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fetched;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const filtered = mapped.filter((channel) => {
|
||||||
|
return channel !== null;
|
||||||
|
});
|
||||||
|
await Promise.all(
|
||||||
|
filtered.map(async(channel) => {
|
||||||
|
await channel.send(
|
||||||
|
// eslint-disable-next-line stylistic/max-len -- This message is too long to fit on one line.
|
||||||
|
"Good morning @everyone~! It's time for standup! Please share your goals for today.",
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
await logger.error("standup module", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await logger.error("standup module", new Error(String(error)));
|
||||||
|
}
|
||||||
|
};
|
12
src/utils/logger.ts
Normal file
12
src/utils/logger.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Logger } from "@nhcarrigan/logger";
|
||||||
|
|
||||||
|
export const logger = new Logger(
|
||||||
|
"Standup Bot",
|
||||||
|
process.env.LOG_TOKEN ?? "",
|
||||||
|
);
|
8
tsconfig.json
Normal file
8
tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "@nhcarrigan/typescript-config",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./prod"
|
||||||
|
},
|
||||||
|
"exclude": ["test/**/*.ts", "vitest.config.ts"]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user