Skip to content

Commit 072a2fd

Browse files
authored
feat: GitHub Actions workflow
2 parents 77149e8 + c457bb8 commit 072a2fd

File tree

14 files changed

+172
-136
lines changed

14 files changed

+172
-136
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,25 @@ on:
99
jobs:
1010
build:
1111
runs-on: ubuntu-latest
12-
1312
steps:
14-
- uses: actions/checkout@v2
15-
- name: Use Node.js
16-
uses: actions/setup-node@v2
13+
- uses: actions/checkout@v4
14+
15+
- name: Use Bun
16+
uses: oven-sh/setup-bun@v2
1717
with:
18-
node-version: "20.x"
19-
- run: npm ci
20-
- run: npm run build --if-present
21-
- run: npm test
22-
- run: npm run lint
18+
bun-version: latest
19+
20+
- name: Install dependencies
21+
run: bun install
22+
23+
- name: Format code
24+
run: bun run format
25+
26+
- name: Lint code
27+
run: bun run lint
28+
29+
- name: Type check
30+
run: bunx tsc --noEmit
31+
32+
- name: Build
33+
run: bunx tsc

eslint.config.mjs

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import globals from "globals";
2-
import path from "node:path";
3-
import { fileURLToPath } from "node:url";
2+
import path from "path";
3+
import { fileURLToPath } from "url";
44
import js from "@eslint/js";
5+
import tseslint from "@typescript-eslint/eslint-plugin";
6+
import tsParser from "@typescript-eslint/parser";
57
import { FlatCompat } from "@eslint/eslintrc";
68

79
const __filename = fileURLToPath(import.meta.url);
@@ -15,62 +17,64 @@ const compat = new FlatCompat({
1517
export default [
1618
...compat.extends("eslint:recommended"),
1719
{
20+
ignores: ["dist/**", "node_modules/**"],
1821
languageOptions: {
22+
parser: tsParser,
23+
parserOptions: {
24+
ecmaVersion: 2021,
25+
sourceType: "module",
26+
},
1927
globals: {
2028
...globals.node,
2129
},
22-
23-
ecmaVersion: 2021,
24-
sourceType: "module", // Changed from "commonjs" to "module"
2530
},
2631

32+
files: ["**/*.{ts,mts,cts}"],
33+
plugins: {
34+
"@typescript-eslint": tseslint,
35+
},
2736
rules: {
37+
// ESLint Core Rules
2838
"arrow-spacing": [
2939
"warn",
3040
{
3141
before: true,
3242
after: true,
3343
},
3444
],
35-
3645
"brace-style": [
3746
"error",
38-
"stroustrup",
47+
"1tbs",
3948
{
4049
allowSingleLine: true,
4150
},
4251
],
43-
4452
"comma-dangle": ["error", "always-multiline"],
4553
"comma-spacing": "error",
4654
"comma-style": "error",
4755
curly: ["error", "multi-line", "consistent"],
4856
"dot-location": ["error", "property"],
4957
"handle-callback-err": "off",
50-
indent: ["error", "tab"],
58+
indent: ["error", 2],
5159
"keyword-spacing": "error",
52-
5360
"max-nested-callbacks": [
5461
"error",
5562
{
5663
max: 4,
5764
},
5865
],
59-
6066
"max-statements-per-line": [
6167
"error",
6268
{
6369
max: 2,
6470
},
6571
],
66-
6772
"no-console": "off",
6873
"no-empty-function": "error",
6974
"no-floating-decimal": "error",
7075
"no-inline-comments": "error",
7176
"no-lonely-if": "error",
7277
"no-multi-spaces": "error",
73-
7478
"no-multiple-empty-lines": [
7579
"error",
7680
{
@@ -79,22 +83,19 @@ export default [
7983
maxBOF: 0,
8084
},
8185
],
82-
8386
"no-shadow": [
8487
"error",
8588
{
8689
allow: ["err", "resolve", "reject"],
8790
},
8891
],
89-
9092
"no-trailing-spaces": ["error"],
9193
"no-var": "error",
9294
"object-curly-spacing": ["error", "always"],
9395
"prefer-const": "error",
9496
quotes: ["error", "double"],
9597
semi: ["error", "always"],
9698
"space-before-blocks": "error",
97-
9899
"space-before-function-paren": [
99100
"error",
100101
{
@@ -103,30 +104,20 @@ export default [
103104
asyncArrow: "always",
104105
},
105106
],
106-
107107
"space-in-parens": "error",
108108
"space-infix-ops": "error",
109109
"space-unary-ops": "error",
110110
"spaced-comment": "error",
111111
yoda: "error",
112112

113-
"no-unused-vars": [
114-
"error",
115-
{
116-
argsIgnorePattern: "^_",
117-
},
118-
],
119-
120-
"no-use-before-define": [
121-
"error",
122-
{
123-
functions: false,
124-
classes: true,
125-
},
126-
],
127-
113+
// TypeScript-Specific Rules
128114
"@typescript-eslint/explicit-function-return-type": "off",
129115
"@typescript-eslint/no-explicit-any": "warn",
116+
117+
// Optional: Strict and Stylistic Rules
118+
...tseslint.configs.recommended.rules,
119+
...tseslint.configs.strict.rules,
120+
...tseslint.configs.stylistic.rules,
130121
},
131122
},
132123
];

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"start": "bun ./dist/index.js",
1010
"watch": "bunx tsc -w",
1111
"format": "bunx prettier --write .",
12-
"lint": "eslint . "
12+
"lint": "eslint . --fix "
1313
},
1414
"keywords": [
1515
"canvas",
@@ -35,9 +35,13 @@
3535
"devDependencies": {
3636
"@eslint/eslintrc": "^3.1.0",
3737
"@eslint/js": "^9.9.1",
38+
"@types/eslint__js": "^8.42.3",
3839
"@types/html-to-text": "^9.0.1",
40+
"@typescript-eslint/eslint-plugin": "^8.3.0",
41+
"@typescript-eslint/parser": "^8.3.0",
3942
"eslint": "^9.9.1",
4043
"globals": "^15.9.0",
41-
"supabase": "^1.191.3"
44+
"supabase": "^1.191.3",
45+
"typescript-eslint": "^8.3.0"
4246
}
4347
}

src/commands/canvas/account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
128128

129129
if (confirmation?.customId === "confirm") {
130130
const schoolResponse = await axios.get(
131-
`https://canvas.instructure.com/api/v1/accounts/search?name=long beach&per_page=5`,
131+
"https://canvas.instructure.com/api/v1/accounts/search?name=long beach&per_page=5",
132132
);
133133
const schools = schoolResponse.data;
134134
const selectedSchool = await chooseSchool(interaction, schools);

src/commands/canvas/assignments.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import axios from "axios";
21
import {
32
SlashCommandBuilder,
43
ActionRowBuilder,
@@ -10,15 +9,18 @@ import {
109
} from "discord.js";
1110
import { randomColor } from "../../helpers/colors";
1211
import { fetchAssignments, fetchCourses } from "../../helpers/api";
12+
import { Course } from "../../types";
1313

1414
export const data = new SlashCommandBuilder()
1515
.setName("assignments")
1616
.setDescription("Display assignments for your courses");
1717

1818
export async function execute(interaction: ChatInputCommandInteraction) {
1919
const userId = interaction.user.id;
20-
const { message, courses } = await fetchCourses(userId);
21-
20+
const { message, courses } = (await fetchCourses(userId)) as {
21+
message: string;
22+
courses: Course[];
23+
};
2224
if (courses.length === 0) {
2325
await interaction.reply({ content: message, ephemeral: true });
2426
return;
@@ -28,7 +30,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
2830
.setCustomId("course_select")
2931
.setPlaceholder("Select a course")
3032
.addOptions(
31-
courses.map((course: { name: string; id: number }) => ({
33+
courses.map((course: Course) => ({
3234
label: course.name,
3335
value: course.id.toString(),
3436
})),

src/commands/canvas/missing.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
SlashCommandBuilder,
55
} from "discord.js";
66
import { randomColor } from "../../helpers/colors";
7-
import { Command, MissingAssignmentResponse } from "../../types";
7+
import { Assignment, Command, MissingAssignmentResponse } from "../../types";
88
import { getAllAssignments } from "../../helpers/api";
99

1010
export const data = new SlashCommandBuilder()
@@ -14,14 +14,15 @@ export const data = new SlashCommandBuilder()
1414

1515
export async function execute(interaction: ChatInputCommandInteraction) {
1616
try {
17-
const data: Command["data"] = {
17+
const commandData: Command["data"] = {
1818
name: "missing",
1919
permissions: [],
2020
aliases: [],
2121
};
2222
const userId: string = interaction.user.id;
23-
const userAssignments: MissingAssignmentResponse =
24-
await getAllAssignments(userId);
23+
const userAssignments: MissingAssignmentResponse = await getAllAssignments(
24+
userId,
25+
);
2526

2627
if (userAssignments.courses.length === 0) {
2728
await interaction.reply({
@@ -31,7 +32,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
3132
return;
3233
}
3334

34-
for (const course of userAssignments.courses) {
35+
for (const course of userAssignments.courses as Assignment[]) {
3536
const title: string = course.name;
3637
const url: string = course.html_url;
3738
const points: number = course.points_possible;
@@ -70,7 +71,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
7071
await interaction.user.send({ embeds: [embed] });
7172
}
7273
await interaction.reply("Missing assignments received in DM's");
73-
return { data };
74+
return { data: commandData };
7475
} catch (error) {
7576
console.error(
7677
"An error occurred while fetching or replying to missing assignments: ",

src/deployCommands.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { REST, Routes } from "discord.js";
1+
import {
2+
REST,
3+
RESTPostAPIApplicationCommandsJSONBody,
4+
Routes,
5+
} from "discord.js";
26
import { readdir } from "fs/promises";
37
import { join } from "path/posix";
48
import { Command } from "./types";
@@ -37,13 +41,13 @@ async function loadCommands() {
3741
`Started refreshing ${commands.length} application (/) commands.`,
3842
);
3943

40-
const data: any = await rest.put(
44+
const data = (await rest.put(
4145
Routes.applicationGuildCommands(
4246
process.env.CLIENT_ID || "",
4347
process.env.GUILD_ID || "",
4448
),
4549
{ body: commands },
46-
);
50+
)) as RESTPostAPIApplicationCommandsJSONBody[];
4751

4852
console.log(
4953
`Successfully reloaded ${data.length} application (/) commands.`,

src/events/assignmentChecker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { EmbedBuilder, Client } from "discord.js";
22
import { randomColor } from "../helpers/colors";
3+
import { Assignment } from "../types";
34

45
export async function postAssignment(
56
userId: string,
6-
assignment: any,
7+
assignment: Assignment,
78
client: Client,
89
): Promise<void> {
910
const {

src/events/interactionCreate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BotEvent } from "../types";
33

44
const clientReadyEvent: BotEvent = {
55
name: Events.InteractionCreate,
6-
execute: async function (interaction) {
6+
execute: async function(interaction) {
77
if (!interaction.isCommand()) return;
88

99
const command = interaction.client.commands.get(interaction.commandName);

src/events/ready.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Client, Events, ActivityType } from "discord.js";
2-
import { BotEvent } from "../types";
2+
import { AnnouncementPost, Assignment, BotEvent } from "../types";
33
import { postAnnouncement } from "./announcements";
44
import { runChecker } from "../helpers/checker";
55
import { getCanvasToken } from "../helpers/supabase";
@@ -14,7 +14,7 @@ const clientReadyEvent: BotEvent = {
1414
client?.user?.setActivity("Your Assignments", {
1515
type: ActivityType.Watching,
1616
});
17-
runChecker(
17+
runChecker<AnnouncementPost>(
1818
client,
1919
async (userId) => {
2020
const token = await getCanvasToken(userId);
@@ -29,7 +29,8 @@ const clientReadyEvent: BotEvent = {
2929
"Error fetching and posting announcements:",
3030
24 * 60 * 60 * 1000,
3131
);
32-
runChecker(
32+
33+
runChecker<Assignment>(
3334
client,
3435
(userId) => fetchAssignmentChecker(userId),
3536
postAssignment,

0 commit comments

Comments
 (0)