From 513a3b60ebb5c4e77be2dae40c67c02d29375a7c Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Mon, 5 Jan 2026 13:48:11 -0500 Subject: [PATCH 1/2] Adding in my changes --- src/commands/github/gh.ts | 50 +++++++++++++---------- src/commands/github/pr.ts | 44 +++++++++++--------- src/services/github/githubErrorMessage.ts | 17 ++++++++ 3 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 src/services/github/githubErrorMessage.ts diff --git a/src/commands/github/gh.ts b/src/commands/github/gh.ts index 3f0d1db6..52872119 100644 --- a/src/commands/github/gh.ts +++ b/src/commands/github/gh.ts @@ -5,12 +5,12 @@ import { SlashCommandBuilder, type ChatInputCommandInteraction, } from "discord.js"; -import { GitHubApiError } from "../../services/github/githubClient.js"; import { getIssue, listIssues, listPullRequests, } from "../../services/github/githubApi.js"; +import { getGitHubUserMessage } from "../../services/github/githubErrorMessage.js"; import { logger } from "../../utils/logger.js"; /** @@ -28,7 +28,9 @@ export const data = new SlashCommandBuilder() .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) + .addStringOption((o) => + o.setName("repo").setDescription("Repo").setRequired(true), + ) .addIntegerOption((o) => o.setName("number").setDescription("Issue #").setRequired(true), ), @@ -41,7 +43,9 @@ export const data = new SlashCommandBuilder() .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) + .addStringOption((o) => + o.setName("repo").setDescription("Repo").setRequired(true), + ) .addIntegerOption((o) => o .setName("limit") @@ -54,11 +58,13 @@ export const data = new SlashCommandBuilder() .addSubcommand((s) => s .setName("prs") - .setDescription("List pull requests") + .setDescription("List open pull requests") .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) + .addStringOption((o) => + o.setName("repo").setDescription("Repo").setRequired(true), + ) .addIntegerOption((o) => o .setName("limit") @@ -68,7 +74,9 @@ export const data = new SlashCommandBuilder() ), ); -export async function execute(interaction: ChatInputCommandInteraction): Promise { +export async function execute( + interaction: ChatInputCommandInteraction, +): Promise { const sub = interaction.options.getSubcommand(true); await interaction.deferReply({ flags: MessageFlags.Ephemeral }); @@ -107,7 +115,8 @@ export async function execute(interaction: ChatInputCommandInteraction): Promise `**Open issues for ${owner}/${repo}**`, "", ...issues.map( - (i) => `#${i.number} ${i.title} (by ${i.user?.login ?? "unknown"})`, + (i) => + `#${i.number} ${i.title} (by ${i.user?.login ?? "unknown"})\n${i.html_url}`, ), ].join("\n"), ); @@ -127,29 +136,26 @@ export async function execute(interaction: ChatInputCommandInteraction): Promise [ `**Open PRs for ${owner}/${repo}**`, "", - ...prs.map((p) => `#${p.number} ${p.title} (by ${p.user?.login ?? "unknown"})`), + ...prs.map( + (p) => + `#${p.number} ${p.title} (by ${p.user?.login ?? "unknown"})\n${p.html_url}`, + ), ].join("\n"), ); return; } - // Should be unreachable because subcommand is required, but keep it safe. await interaction.editReply("Unknown subcommand."); + return; } catch (err) { - if (err instanceof GitHubApiError) { - if (err.status === 404) { - await interaction.editReply("Not found. Check owner/repo and the number."); - return; - } - - logger.warn({ err, owner, repo, sub }, "[gh] GitHub API error"); - - await interaction.editReply(`GitHub error (${err.status}): ${err.message}`); + const msg = getGitHubUserMessage(err); + if (msg) { + await interaction.editReply(msg); return; } - logger.error({ err, owner, repo, sub }, "[gh] command failed"); - - await interaction.editReply("Something went wrong talking to GitHub."); + logger.warn({ err, owner, repo, sub }, "[gh] GitHub request failed"); + await interaction.editReply("GitHub request failed. Please try again in a bit."); + return; } -} +} \ No newline at end of file diff --git a/src/commands/github/pr.ts b/src/commands/github/pr.ts index d3aea2a0..c3883388 100644 --- a/src/commands/github/pr.ts +++ b/src/commands/github/pr.ts @@ -5,8 +5,8 @@ import { SlashCommandBuilder, type ChatInputCommandInteraction, } from "discord.js"; -import { GitHubApiError } from "../../services/github/githubClient.js"; import { getPullRequest } from "../../services/github/githubApi.js"; +import { getGitHubUserMessage } from "../../services/github/githubErrorMessage.js"; import { logger } from "../../utils/logger.js"; /** @@ -15,12 +15,20 @@ import { logger } from "../../utils/logger.js"; */ export const data = new SlashCommandBuilder() .setName("pr") - .setDescription("GitHub pull request helpers") - .addIntegerOption((o) => o.setName("number").setDescription("PR #").setRequired(true)) - .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true)) - .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)); + .setDescription("Fetch a GitHub pull request by number") + .addIntegerOption((o) => + o.setName("number").setDescription("PR #").setRequired(true), + ) + .addStringOption((o) => + o.setName("owner").setDescription("Org/user").setRequired(true), + ) + .addStringOption((o) => + o.setName("repo").setDescription("Repo").setRequired(true), + ); -export async function execute(interaction: ChatInputCommandInteraction): Promise { +export async function execute( + interaction: ChatInputCommandInteraction, +): Promise { await interaction.deferReply({ flags: MessageFlags.Ephemeral }); const owner = interaction.options.getString("owner", true); @@ -31,30 +39,26 @@ export async function execute(interaction: ChatInputCommandInteraction): Promise const pr = await getPullRequest(owner, repo, number); const mergedLabel = pr.merged ? "merged" : "not merged"; + const body = [ `**${owner}/${repo} PR #${pr.number}**`, pr.title, `State: ${pr.state} (${mergedLabel})`, `Author: ${pr.user?.login ?? "unknown"}`, - `URL: ${pr.html_url}`, + pr.html_url, ].join("\n"); await interaction.editReply(body); + return; } catch (err) { - if (err instanceof GitHubApiError) { - if (err.status === 404) { - await interaction.editReply("PR not found. Check owner/repo and PR number."); - return; - } - - logger.warn({ err, owner, repo, number }, "[pr] GitHub API error"); - - await interaction.editReply(`GitHub API error (${err.status}): ${err.message}`); + const msg = getGitHubUserMessage(err); + if (msg) { + await interaction.editReply(msg); return; } - logger.error({ err, owner, repo, number }, "[pr] command failed"); - - await interaction.editReply("Something went wrong while talking to GitHub."); + logger.warn({ err, owner, repo, number }, "[pr] GitHub request failed"); + await interaction.editReply("GitHub request failed. Please try again in a bit."); + return; } -} +} \ No newline at end of file diff --git a/src/services/github/githubErrorMessage.ts b/src/services/github/githubErrorMessage.ts new file mode 100644 index 00000000..0d27afe2 --- /dev/null +++ b/src/services/github/githubErrorMessage.ts @@ -0,0 +1,17 @@ +import { GitHubApiError } from "./githubClient.js"; + +export function getGitHubUserMessage(err: unknown): string | null { + if (!(err instanceof GitHubApiError)) return null; + + switch (err.status) { + case 404: + return "I could not find that PR. Double check the number and repo."; + case 401: + case 403: + return "I cannot access that repo with the current GitHub token. Check token and repo permissions."; + case 429: + return "GitHub rate limited me. Try again in a bit."; + default: + return null; + } +} From 0c9c88a2d88efd0a8aa0640f65bbdce42d7479c0 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Mon, 5 Jan 2026 13:49:50 -0500 Subject: [PATCH 2/2] Fixing formating --- src/commands/github/gh.ts | 18 +++++------------- src/commands/github/pr.ts | 18 +++++------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/commands/github/gh.ts b/src/commands/github/gh.ts index 52872119..8ed1acb7 100644 --- a/src/commands/github/gh.ts +++ b/src/commands/github/gh.ts @@ -28,9 +28,7 @@ export const data = new SlashCommandBuilder() .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => - o.setName("repo").setDescription("Repo").setRequired(true), - ) + .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) .addIntegerOption((o) => o.setName("number").setDescription("Issue #").setRequired(true), ), @@ -43,9 +41,7 @@ export const data = new SlashCommandBuilder() .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => - o.setName("repo").setDescription("Repo").setRequired(true), - ) + .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) .addIntegerOption((o) => o .setName("limit") @@ -62,9 +58,7 @@ export const data = new SlashCommandBuilder() .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true), ) - .addStringOption((o) => - o.setName("repo").setDescription("Repo").setRequired(true), - ) + .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)) .addIntegerOption((o) => o .setName("limit") @@ -74,9 +68,7 @@ export const data = new SlashCommandBuilder() ), ); -export async function execute( - interaction: ChatInputCommandInteraction, -): Promise { +export async function execute(interaction: ChatInputCommandInteraction): Promise { const sub = interaction.options.getSubcommand(true); await interaction.deferReply({ flags: MessageFlags.Ephemeral }); @@ -158,4 +150,4 @@ export async function execute( await interaction.editReply("GitHub request failed. Please try again in a bit."); return; } -} \ No newline at end of file +} diff --git a/src/commands/github/pr.ts b/src/commands/github/pr.ts index c3883388..9d1c60c5 100644 --- a/src/commands/github/pr.ts +++ b/src/commands/github/pr.ts @@ -16,19 +16,11 @@ import { logger } from "../../utils/logger.js"; export const data = new SlashCommandBuilder() .setName("pr") .setDescription("Fetch a GitHub pull request by number") - .addIntegerOption((o) => - o.setName("number").setDescription("PR #").setRequired(true), - ) - .addStringOption((o) => - o.setName("owner").setDescription("Org/user").setRequired(true), - ) - .addStringOption((o) => - o.setName("repo").setDescription("Repo").setRequired(true), - ); + .addIntegerOption((o) => o.setName("number").setDescription("PR #").setRequired(true)) + .addStringOption((o) => o.setName("owner").setDescription("Org/user").setRequired(true)) + .addStringOption((o) => o.setName("repo").setDescription("Repo").setRequired(true)); -export async function execute( - interaction: ChatInputCommandInteraction, -): Promise { +export async function execute(interaction: ChatInputCommandInteraction): Promise { await interaction.deferReply({ flags: MessageFlags.Ephemeral }); const owner = interaction.options.getString("owner", true); @@ -61,4 +53,4 @@ export async function execute( await interaction.editReply("GitHub request failed. Please try again in a bit."); return; } -} \ No newline at end of file +}