Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: help command #56

Merged
2 changes: 2 additions & 0 deletions src/github/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EmitterWebhookEvent } from "@octokit/webhooks";
import { GitHubContext } from "../github-context";
import { GitHubEventHandler } from "../github-event-handler";
import { getConfig } from "../utils/config";
import issueCommentCreated from "./issue-comment-created";
import { repositoryDispatch } from "./repository-dispatch";
import { dispatchWorker, dispatchWorkflow, getDefaultBranch } from "../utils/workflow-dispatch";
import { PluginInput } from "../types/plugin";
Expand All @@ -19,6 +20,7 @@ function tryCatchWrapper(fn: (event: EmitterWebhookEvent) => unknown) {

export function bindHandlers(eventHandler: GitHubEventHandler) {
eventHandler.on("repository_dispatch", repositoryDispatch);
eventHandler.on("issue_comment.created", issueCommentCreated);
eventHandler.onAny(tryCatchWrapper((event) => handleEvent(event, eventHandler))); // onAny should also receive GithubContext but the types in octokit/webhooks are weird
}

Expand Down
36 changes: 36 additions & 0 deletions src/github/handlers/issue-comment-created.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { GitHubContext } from "../github-context";
import { getConfig } from "../utils/config";

export default async function issueCommentCreated(context: GitHubContext<"issue_comment.created">) {
const body = context.payload.comment.body.trim();
if (/^\/help$/.test(body)) {
const comments = [
"### Available Commands\n\n",
"| Command | Description | Example |",
"|---|---|---|",
"| `/help` | List all available commands. | `/help` |",
];
const configuration = await getConfig(context);
for (const pluginArray of Object.values(configuration.plugins)) {
for (const plugin of pluginArray) {
// Only show plugins that have commands available for the user
if (plugin.command) {
comments.push(`| \`${getContent(plugin.command)}\` | ${getContent(plugin.description)} | \`${getContent(plugin.example)}\` |`);
}
}
}
await context.octokit.issues.createComment({
body: comments.join("\n"),
issue_number: context.payload.issue.number,
rndquu marked this conversation as resolved.
Show resolved Hide resolved
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
});
}
}

/**
* Ensures that passed content does not break MD display within the table.
*/
function getContent(content: string | undefined) {
return content ? content.replace("|", "\\|") : "-";
}
85 changes: 85 additions & 0 deletions tests/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods";
import { afterAll, afterEach, beforeAll, describe, expect, it, mock, spyOn } from "bun:test";
import { config } from "dotenv";
import { GitHubContext } from "../src/github/github-context";
import { GitHubEventHandler } from "../src/github/github-event-handler";
import issueCommentCreated from "../src/github/handlers/issue-comment-created";
import { server } from "./__mocks__/node";
import { WebhooksMocked } from "./__mocks__/webhooks";

void mock.module("@octokit/webhooks", () => ({
Webhooks: WebhooksMocked,
}));

config({ path: ".dev.vars" });

beforeAll(() => {
server.listen();
});
afterEach(() => {
server.resetHandlers();
});
afterAll(() => {
server.close();
});

describe("Event related tests", () => {
it("Should post the help menu when /help command is invoked", async () => {
const issues = {
createComment(params?: RestEndpointMethodTypes["issues"]["createComment"]["parameters"]) {
return params;
},
};
const spy = spyOn(issues, "createComment");
await issueCommentCreated({
id: "",
key: "issue_comment.created",
octokit: {
issues,
rest: {
repos: {
getContent() {
return {
data: `
plugins:
issue_comment.created:
- name: "Run on comment created"
description: "Plugin A"
example: /command [foo | bar]
command: /command
uses:
- id: plugin-A
plugin: https://plugin-a.internal
`,
};
},
},
},
},
eventHandler: {} as GitHubEventHandler,
payload: {
repository: {
owner: { login: "ubiquity" },
name: "ubiquibot-kernel",
},
issue: { number: 1 },
comment: {
body: "/help",
},
} as unknown as GitHubContext<"issue_comment.created">["payload"],
} as unknown as GitHubContext);
expect(spy).toBeCalledTimes(1);
expect(spy.mock.calls).toEqual([
[
{
body:
"### Available Commands\n\n\n| Command | Description | Example |\n|---|---|---|\n| `/help` | List" +
" all available commands. | `/help` |\n| `/command` | Plugin A | `/command [foo \\| bar]` |",
issue_number: 1,
owner: "ubiquity",
repo: "ubiquibot-kernel",
},
],
]);
});
});
Loading