From a45b7f4455424fbbf8fc46d2d65519b96aeb0517 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:13:24 +0000 Subject: [PATCH 1/8] Fix a random GitHub issue --- src/Connections/GithubRepo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connections/GithubRepo.ts b/src/Connections/GithubRepo.ts index f33e267b..4276626d 100644 --- a/src/Connections/GithubRepo.ts +++ b/src/Connections/GithubRepo.ts @@ -288,7 +288,7 @@ export class GitHubRepoConnection implements IConnection { } const orgRepoName = event.repository.full_name; - const content = emoji.emojify(`${event.issue.user?.login} created new issue [${orgRepoName}#${event.issue.number}](${event.issue}): "${event.issue.title}"`); + const content = emoji.emojify(`${event.issue.user?.login} created new issue [${orgRepoName}#${event.issue.number}](${event.issue.html_url}): "${event.issue.title}"`); const { labelsHtml, labelsStr } = FormatUtil.formatLabels(event.issue.labels); await this.as.botIntent.sendEvent(this.roomId, { msgtype: "m.notice", From bc7abf5da58b9f4e11bc46393aaa476fcc518e0c Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:13:47 +0000 Subject: [PATCH 2/8] Add generic webhooks --- src/Connections/GenericHook.ts | 86 ++++++++++++++++++++++++++++++++++ src/GithubBridge.ts | 75 ++++++++++++++++++----------- src/Webhooks.ts | 40 +++++++++++++++- 3 files changed, 172 insertions(+), 29 deletions(-) create mode 100644 src/Connections/GenericHook.ts diff --git a/src/Connections/GenericHook.ts b/src/Connections/GenericHook.ts new file mode 100644 index 00000000..e2214cca --- /dev/null +++ b/src/Connections/GenericHook.ts @@ -0,0 +1,86 @@ +import { IConnection } from "./IConnection"; +import { Appservice } from "matrix-bot-sdk"; +import LogWrapper from "../LogWrapper"; +import { CommentProcessor } from "../CommentProcessor"; +import { MessageSenderClient } from "../MatrixSender" +import markdownit from "markdown-it"; +import { Script, createContext } from "vm"; +import { MatrixEvent } from "../MatrixEvent"; + +export interface GenericHookConnectionState { + hookId: string; + transformationFunction?: string; +} + +const log = new LogWrapper("GenericHookConnection"); +const md = new markdownit(); + +/** + * Handles rooms connected to a github repo. + */ +export class GenericHookConnection implements IConnection { + static readonly CanonicalEventType = "uk.half-shot.matrix-github.generic.hook"; + + static readonly EventTypes = [ + GenericHookConnection.CanonicalEventType, + ]; + + public get hookId() { + return this.state.hookId; + } + + private transformationFunction?: Script; + + constructor(public readonly roomId: string, + private state: GenericHookConnectionState, + private readonly stateKey: string, + private messageClient: MessageSenderClient) { + if (state.transformationFunction) { + this.transformationFunction = new Script(state.transformationFunction); + } + } + + public isInterestedInStateEvent(eventType: string, stateKey: string) { + return GenericHookConnection.EventTypes.includes(eventType) && this.stateKey === stateKey; + } + + public async onStateUpdate(stateEv: MatrixEvent) { + const state = stateEv.content as GenericHookConnectionState; + if (state.transformationFunction) { + try { + this.transformationFunction = new Script(state.transformationFunction); + } catch (ex) { + await this.messageClient.sendMatrixText(this.roomId, 'Could not compile transformation function:' + ex); + } + } + } + + public async onGenericHook(data: Record) { + log.info(`onGenericHook ${this.roomId} ${this.hookId}`); + let content: string; + if (!this.transformationFunction) { + content = `Recieved webhook data:\n\n\`\`\`${JSON.stringify(data)}\`\`\``; + } else { + const context = createContext({data}); + this.transformationFunction.runInContext(context); + if (context.result) { + content = `Recieved webhook: ${context.result}`; + } else { + content = `No content`; + } + } + + return this.messageClient.sendMatrixMessage(this.roomId, { + msgtype: "m.notice", + body: content, + formatted_body: md.renderInline(content), + format: "org.matrix.custom.html", + "uk.half-shot.webhook_data": data, + }); + + } + + public toString() { + return `GenericHookConnection ${this.hookId}`; + } +} \ No newline at end of file diff --git a/src/GithubBridge.ts b/src/GithubBridge.ts index fa61ee6a..f7fb2057 100644 --- a/src/GithubBridge.ts +++ b/src/GithubBridge.ts @@ -1,36 +1,36 @@ +import { AdminRoom, BRIDGE_ROOM_TYPE, AdminAccountData } from "./AdminRoom"; import { Appservice, IAppserviceRegistration, RichRepliesPreprocessor, IRichReplyMetadata, StateEvent, PantalaimonClient, MatrixClient } from "matrix-bot-sdk"; import { BridgeConfig, GitLabInstance } from "./Config/Config"; -import { OAuthRequest, OAuthTokens, NotificationsEnableEvent, NotificationsDisableEvent,} from "./Webhooks"; +import { BridgeWidgetApi } from "./Widgets/BridgeWidgetApi"; import { CommentProcessor } from "./CommentProcessor"; -import { MessageQueue, createMessageQueue } from "./MessageQueue/MessageQueue"; -import { AdminRoom, BRIDGE_ROOM_TYPE, AdminAccountData } from "./AdminRoom"; -import { UserTokenStore } from "./UserTokenStore"; -import { MatrixEvent, MatrixMemberContent, MatrixMessageContent } from "./MatrixEvent"; -import LogWrapper from "./LogWrapper"; -import { MessageSenderClient } from "./MatrixSender"; -import { UserNotificationsEvent } from "./Notifications/UserNotificationWatcher"; -import { RedisStorageProvider } from "./Stores/RedisStorageProvider"; -import { MemoryStorageProvider } from "./Stores/MemoryStorageProvider"; -import { NotificationProcessor } from "./NotificationsProcessor"; -import { IBridgeStorageProvider } from "./Stores/StorageProvider"; -import { retry } from "./PromiseUtil"; -import { IConnection, GitHubDiscussionSpace, GitHubDiscussionConnection, GitHubUserSpace -} from "./Connections"; -import { GitHubRepoConnection } from "./Connections/GithubRepo"; +import { GetIssueResponse, GetIssueOpts } from "./Gitlab/Types" +import { GenericHookConnection } from "./Connections/GenericHook"; +import { GithubInstance } from "./Github/GithubInstance"; import { GitHubIssueConnection } from "./Connections/GithubIssue"; import { GitHubProjectConnection } from "./Connections/GithubProject"; -import { GitLabRepoConnection } from "./Connections/GitlabRepo"; -import { GithubInstance } from "./Github/GithubInstance"; -import { IGitLabWebhookIssueStateEvent, IGitLabWebhookMREvent, IGitLabWebhookNoteEvent } from "./Gitlab/WebhookTypes"; -import { GitLabIssueConnection } from "./Connections/GitlabIssue"; -import { GetIssueResponse, GetIssueOpts } from "./Gitlab/Types" +import { GitHubRepoConnection } from "./Connections/GithubRepo"; import { GitLabClient } from "./Gitlab/Client"; -import { BridgeWidgetApi } from "./Widgets/BridgeWidgetApi"; -import { ProjectsGetResponseData } from "./Github/Types"; -import { NotifFilter, NotificationFilterStateContent } from "./NotificationFilters"; -import * as GitHubWebhookTypes from "@octokit/webhooks-types"; -import { JiraCommentCreatedEvent, JiraIssueEvent } from "./Jira/WebhookTypes"; +import { GitLabIssueConnection } from "./Connections/GitlabIssue"; +import { GitLabRepoConnection } from "./Connections/GitlabRepo"; +import { IBridgeStorageProvider } from "./Stores/StorageProvider"; +import { IConnection, GitHubDiscussionSpace, GitHubDiscussionConnection, GitHubUserSpace } from "./Connections"; +import { IGitLabWebhookIssueStateEvent, IGitLabWebhookMREvent, IGitLabWebhookNoteEvent } from "./Gitlab/WebhookTypes"; +import { JiraIssueEvent } from "./Jira/WebhookTypes"; import { JiraProjectConnection } from "./Connections/JiraProject"; +import { MatrixEvent, MatrixMemberContent, MatrixMessageContent } from "./MatrixEvent"; +import { MemoryStorageProvider } from "./Stores/MemoryStorageProvider"; +import { MessageQueue, createMessageQueue } from "./MessageQueue/MessageQueue"; +import { MessageSenderClient } from "./MatrixSender"; +import { NotifFilter, NotificationFilterStateContent } from "./NotificationFilters"; +import { NotificationProcessor } from "./NotificationsProcessor"; +import { OAuthRequest, OAuthTokens, NotificationsEnableEvent, NotificationsDisableEvent, GenericWebhookEvent,} from "./Webhooks"; +import { ProjectsGetResponseData } from "./Github/Types"; +import { RedisStorageProvider } from "./Stores/RedisStorageProvider"; +import { retry } from "./PromiseUtil"; +import { UserNotificationsEvent } from "./Notifications/UserNotificationWatcher"; +import { UserTokenStore } from "./UserTokenStore"; +import * as GitHubWebhookTypes from "@octokit/webhooks-types"; +import LogWrapper from "./LogWrapper"; const log = new LogWrapper("GithubBridge"); @@ -137,6 +137,10 @@ export class GithubBridge { return new JiraProjectConnection(roomId, this.as, state.content, state.stateKey, this.commentProcessor, this.messageClient); } + if (GenericHookConnection.EventTypes.includes(state.type)) { + return new GenericHookConnection(roomId, state.content, state.stateKey, this.messageClient); + } + return; } @@ -217,6 +221,11 @@ export class GithubBridge { return this.connections.filter((c) => (c instanceof JiraProjectConnection && c.projectId === projectId)) as JiraProjectConnection[]; } + private getConnectionsForGenericWebhook(hookId: string): GenericHookConnection[] { + return this.connections.filter((c) => (c instanceof GenericHookConnection && c.hookId === hookId)) as GenericHookConnection[]; + } + + public stop() { this.as.stop(); if(this.queue.stop) this.queue.stop(); @@ -602,7 +611,6 @@ export class GithubBridge { log.info(`JIRA issue created for project ${data.issue.fields.project.id}, issue id ${data.issue.id}`); const projectId = data.issue.fields.project.id; const connections = this.getConnectionsForJiraProject(projectId); - console.log(data.issue.fields.project); connections.forEach(async (c) => { try { @@ -612,6 +620,19 @@ export class GithubBridge { } }); }); + + this.queue.on("generic-webhook.event", async ({data}) => { + log.info(`Incoming generic hook ${data.hookId}`); + const connections = this.getConnectionsForGenericWebhook(data.hookId); + + connections.forEach(async (c) => { + try { + await c.onGenericHook(data.hookData); + } catch (ex) { + log.warn(`Failed to handle generic-webhook.event:`, ex); + } + }); + }); // Fetch all room state let joinedRooms: string[]|undefined; diff --git a/src/Webhooks.ts b/src/Webhooks.ts index 23f23263..49f72fa8 100644 --- a/src/Webhooks.ts +++ b/src/Webhooks.ts @@ -11,6 +11,11 @@ import { EmitterWebhookEvent, Webhooks as OctokitWebhooks } from "@octokit/webho import { IJiraWebhookEvent, JiraIssueEvent } from "./Jira/WebhookTypes"; const log = new LogWrapper("GithubWebhooks"); +export interface GenericWebhookEvent { + hookData: Record; + hookId: string; +} + export interface OAuthRequest { code: string; state: string; @@ -55,6 +60,12 @@ export class Webhooks extends EventEmitter { this.ghWebhooks.onAny(e => this.onGitHubPayload(e)); } + this.expressApp.all( + '/:hookId', + express.json({ type: ['application/json', 'application/x-www-form-urlencoded'] }), + this.onGenericPayload.bind(this), + ); + this.expressApp.use(express.json({ verify: this.verifyRequest.bind(this), })); @@ -81,6 +92,7 @@ export class Webhooks extends EventEmitter { } } + private onGitLabPayload(body: IGitLabWebhookEvent) { log.info(`onGitLabPayload ${body.event_type}:`, body); if (body.event_type === "merge_request") { @@ -118,6 +130,32 @@ export class Webhooks extends EventEmitter { } } + private onGenericPayload(req: Request, res: Response) { + if (!['PUT', 'GET', 'POST'].includes(req.method)) { + res.sendStatus(400).send({error: 'Wrong METHOD. Expecting PUT,GET,POST'}); + return; + } + + let body; + if (req.method === 'GET') { + body = req.query; + } else { + body = req.body; + } + + res.sendStatus(200); + this.queue.push({ + eventName: 'generic-webhook.event', + sender: "GithubWebhooks", + data: { + hookData: body, + hookId: req.params.hookId, + } as GenericWebhookEvent, + }).catch((err) => { + log.error(`Failed to emit payload: ${err}`); + }); + } + private onPayload(req: Request, res: Response) { log.info(`New webhook: ${req.url}`); try { @@ -236,8 +274,6 @@ export class Webhooks extends EventEmitter { } return true; } - console.log(req.body); - console.log(req.headers); log.error(`No signature on URL. Rejecting`); res.sendStatus(400); throw Error("Invalid signature."); From cc9ae2491cb4cc6150ee68ea2b01ebe38e500987 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:20:13 +0000 Subject: [PATCH 3/8] Ensure generic webhooks can be configured --- src/Config/Config.ts | 8 ++++++++ src/Config/Defaults.ts | 9 +++++++++ src/Connections/GenericHook.ts | 7 ++++--- src/GithubBridge.ts | 10 ++++++++-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Config/Config.ts b/src/Config/Config.ts index 31bb6e56..304dd10a 100644 --- a/src/Config/Config.ts +++ b/src/Config/Config.ts @@ -45,6 +45,11 @@ interface BridgeConfigJira { }; } +interface BridgeGenericWebhooksConfig { + enabled: boolean; + allowJsTransformationFunctions?: boolean; +} + interface BridgeWidgetConfig { port: number; addToAdminRooms: boolean; @@ -95,6 +100,7 @@ interface BridgeConfigRoot { jira?: BridgeConfigJira; bot?: BridgeConfigBot; widgets?: BridgeWidgetConfig; + generic?: BridgeGenericWebhooksConfig; } export class BridgeConfig { @@ -115,6 +121,8 @@ export class BridgeConfig { public readonly gitlab?: BridgeConfigGitLab; @configKey("Configure this to enable Jira support") public readonly jira?: BridgeConfigJira; + @configKey("Support for generic webhook events. `allowJsTransformationFunctions` will allow users to write short transformation snippets in code, and thus is unsafe in untrusted environments", true) + public readonly generic?: BridgeGenericWebhooksConfig; @configKey("Define profile information for the bot user", true) public readonly bot?: BridgeConfigBot; @configKey("EXPERIMENTAL support for complimentary widgets", true) diff --git a/src/Config/Defaults.ts b/src/Config/Defaults.ts index dce8c8cc..fe64937d 100644 --- a/src/Config/Defaults.ts +++ b/src/Config/Defaults.ts @@ -58,6 +58,15 @@ const DefaultConfig = new BridgeConfig({ webhook: { secret: "secrettoken", } + }, + jira: { + webhook: { + secret: 'secrettoken' + } + }, + generic: { + enabled: false, + allowJsTransformationFunctions: false, } }, {}); diff --git a/src/Connections/GenericHook.ts b/src/Connections/GenericHook.ts index e2214cca..1a1b34b0 100644 --- a/src/Connections/GenericHook.ts +++ b/src/Connections/GenericHook.ts @@ -34,8 +34,9 @@ export class GenericHookConnection implements IConnection { constructor(public readonly roomId: string, private state: GenericHookConnectionState, private readonly stateKey: string, - private messageClient: MessageSenderClient) { - if (state.transformationFunction) { + private messageClient: MessageSenderClient, + private readonly allowJSTransformation: boolean = false) { + if (state.transformationFunction && allowJSTransformation) { this.transformationFunction = new Script(state.transformationFunction); } } @@ -46,7 +47,7 @@ export class GenericHookConnection implements IConnection { public async onStateUpdate(stateEv: MatrixEvent) { const state = stateEv.content as GenericHookConnectionState; - if (state.transformationFunction) { + if (state.transformationFunction && this.allowJSTransformation) { try { this.transformationFunction = new Script(state.transformationFunction); } catch (ex) { diff --git a/src/GithubBridge.ts b/src/GithubBridge.ts index f7fb2057..113592f7 100644 --- a/src/GithubBridge.ts +++ b/src/GithubBridge.ts @@ -137,8 +137,14 @@ export class GithubBridge { return new JiraProjectConnection(roomId, this.as, state.content, state.stateKey, this.commentProcessor, this.messageClient); } - if (GenericHookConnection.EventTypes.includes(state.type)) { - return new GenericHookConnection(roomId, state.content, state.stateKey, this.messageClient); + if (GenericHookConnection.EventTypes.includes(state.type) && this.config.generic?.enabled) { + return new GenericHookConnection( + roomId, + state.content, + state.stateKey, + this.messageClient, + this.config.generic.allowJsTransformationFunctions + ); } return; From 5976eef79099fa21f50ec9f555dfe775ab0a1e0f Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:27:09 +0000 Subject: [PATCH 4/8] Add a timeout so we don't burn CPU on these --- src/Connections/GenericHook.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Connections/GenericHook.ts b/src/Connections/GenericHook.ts index 1a1b34b0..940d9bec 100644 --- a/src/Connections/GenericHook.ts +++ b/src/Connections/GenericHook.ts @@ -1,7 +1,5 @@ import { IConnection } from "./IConnection"; -import { Appservice } from "matrix-bot-sdk"; import LogWrapper from "../LogWrapper"; -import { CommentProcessor } from "../CommentProcessor"; import { MessageSenderClient } from "../MatrixSender" import markdownit from "markdown-it"; import { Script, createContext } from "vm"; @@ -15,6 +13,8 @@ export interface GenericHookConnectionState { const log = new LogWrapper("GenericHookConnection"); const md = new markdownit(); +const TRANSFORMATION_TIMEOUT_MS = 2000; + /** * Handles rooms connected to a github repo. */ @@ -62,12 +62,20 @@ export class GenericHookConnection implements IConnection { if (!this.transformationFunction) { content = `Recieved webhook data:\n\n\`\`\`${JSON.stringify(data)}\`\`\``; } else { - const context = createContext({data}); - this.transformationFunction.runInContext(context); - if (context.result) { - content = `Recieved webhook: ${context.result}`; - } else { - content = `No content`; + try { + const context = createContext({data}); + this.transformationFunction.runInContext(context, { + timeout: TRANSFORMATION_TIMEOUT_MS, + breakOnSigint: true, + filename: `generic-hook.${this.hookId}`, + }); + if (context.result) { + content = `Recieved webhook: ${context.result}`; + } else { + content = `No content`; + } + } catch (ex) { + content = `Webhook recieved but failed to process via transformation function`; } } From 537352fbf317680680a4523229a8e0b0868f5ed5 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:29:34 +0000 Subject: [PATCH 5/8] Update default config --- config.sample.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config.sample.yml b/config.sample.yml index 6db1051b..154dad66 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -9,7 +9,7 @@ bridge: port: 9993 bindAddress: 127.0.0.1 github: - # (Optional) Configure this to enable support for GitHub + # (Optional) Configure this to enable GitHub support # installationId: 6854059 auth: @@ -22,13 +22,17 @@ github: webhook: secret: secrettoken gitlab: - # (Optional) Configure this to enable support for GitLab + # (Optional) Configure this to enable GitLab support # instances: gitlab.com: url: https://gitlab.com webhook: secret: secrettoken +jira: + # Configure this to enable Jira support + # + null webhook: # HTTP webhook listener options # From 982f5ee249615c3668dabf4019f2b1ec7eaa5d3d Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 12:31:01 +0000 Subject: [PATCH 6/8] Fix config --- config.sample.yml | 8 +++++++- src/Config/Config.ts | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config.sample.yml b/config.sample.yml index 154dad66..c2bc27d0 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -32,7 +32,13 @@ gitlab: jira: # Configure this to enable Jira support # - null + webhook: + secret: secrettoken +generic: + # (Optional) Support for generic webhook events. `allowJsTransformationFunctions` will allow users to write short transformation snippets in code, and thus is unsafe in untrusted environments + # + enabled: false + allowJsTransformationFunctions: false webhook: # HTTP webhook listener options # diff --git a/src/Config/Config.ts b/src/Config/Config.ts index 304dd10a..2d84cacc 100644 --- a/src/Config/Config.ts +++ b/src/Config/Config.ts @@ -119,7 +119,7 @@ export class BridgeConfig { public readonly github?: BridgeConfigGitHub; @configKey("Configure this to enable GitLab support", true) public readonly gitlab?: BridgeConfigGitLab; - @configKey("Configure this to enable Jira support") + @configKey("Configure this to enable Jira support", true) public readonly jira?: BridgeConfigJira; @configKey("Support for generic webhook events. `allowJsTransformationFunctions` will allow users to write short transformation snippets in code, and thus is unsafe in untrusted environments", true) public readonly generic?: BridgeGenericWebhooksConfig; @@ -140,6 +140,7 @@ export class BridgeConfig { } this.gitlab = configData.gitlab; this.jira = configData.jira; + this.generic = configData.generic; this.webhook = configData.webhook; this.passFile = configData.passFile; assert.ok(this.webhook); From a6676d4d4fb636780bef4bacc78e6347f81e9d05 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 14:22:44 +0000 Subject: [PATCH 7/8] Fix tests --- src/Connections/GithubIssue.ts | 2 +- src/Connections/GithubUserSpace.ts | 3 ++- src/Connections/GitlabRepo.ts | 8 -------- tests/AdminRoomTest.ts | 2 +- tests/FormatUtilTest.ts | 2 ++ 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Connections/GithubIssue.ts b/src/Connections/GithubIssue.ts index b56135fc..70c3b341 100644 --- a/src/Connections/GithubIssue.ts +++ b/src/Connections/GithubIssue.ts @@ -316,7 +316,7 @@ export class GitHubIssueConnection implements IConnection { } } - public onIssueStateChange(data?: any) { + public onIssueStateChange(data: unknown) { return this.syncIssueState(); } diff --git a/src/Connections/GithubUserSpace.ts b/src/Connections/GithubUserSpace.ts index 2256df4d..e98fc59e 100644 --- a/src/Connections/GithubUserSpace.ts +++ b/src/Connections/GithubUserSpace.ts @@ -55,7 +55,8 @@ export class GitHubUserSpace implements IConnection { throw Error("Could not find repo"); } - let avatarState: any|undefined; + // eslint-disable-next-line camelcase + let avatarState: {type: "m.room.avatar", state_key: "", content: { url: string}}|undefined; try { if (avatarUrl) { const res = await axios.get(avatarUrl, { diff --git a/src/Connections/GitlabRepo.ts b/src/Connections/GitlabRepo.ts index 96737e6f..d70ebefa 100644 --- a/src/Connections/GitlabRepo.ts +++ b/src/Connections/GitlabRepo.ts @@ -131,14 +131,6 @@ export class GitLabRepoConnection implements IConnection { }); } - // public async onIssueCreated(event: IGitHubWebhookEvent) { - - // } - - // public async onIssueStateChange(event: IGitHubWebhookEvent) { - - // } - public toString() { return `GitHubRepo`; } diff --git a/tests/AdminRoomTest.ts b/tests/AdminRoomTest.ts index fbc8a8c0..97cc2c7d 100644 --- a/tests/AdminRoomTest.ts +++ b/tests/AdminRoomTest.ts @@ -24,7 +24,7 @@ describe("AdminRoom", () => { expect(intent.sentEvents[0]).to.deep.equal({ roomId: ROOM_ID, - content: AdminRoom.helpMessage, + content: AdminRoom.helpMessage(), }); }); }) \ No newline at end of file diff --git a/tests/FormatUtilTest.ts b/tests/FormatUtilTest.ts index 7baab0ce..65be1449 100644 --- a/tests/FormatUtilTest.ts +++ b/tests/FormatUtilTest.ts @@ -2,6 +2,7 @@ import { FormatUtil } from "../src/FormatUtil"; import { expect } from "chai"; const SIMPLE_ISSUE = { + id: 123, number: 123, state: "open", title: "A simple title", @@ -12,6 +13,7 @@ const SIMPLE_ISSUE = { }; const SIMPLE_REPO = { + id: 123, description: "A simple description", full_name: "evilcorp/lab", html_url: "https://github.com/evilcorp/lab/issues/123", From 8b584f2622ffb2207d585849472d3f4d7be5969e Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 17 Nov 2021 14:24:32 +0000 Subject: [PATCH 8/8] One more config edit --- config.sample.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.sample.yml b/config.sample.yml index c2bc27d0..b732f5f1 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -30,7 +30,7 @@ gitlab: webhook: secret: secrettoken jira: - # Configure this to enable Jira support + # (Optional) Configure this to enable Jira support # webhook: secret: secrettoken