Update dependencies

This commit is contained in:
Will Hunt 2021-04-11 15:18:49 +01:00
parent 94c6c65ed2
commit 745f628e7a
24 changed files with 1268 additions and 2118 deletions

View File

@ -22,53 +22,52 @@
"generate-default-config": "node lib/Config/Defaults.js > config.sample.yml"
},
"dependencies": {
"@octokit/auth-app": "2.10.2",
"@octokit/auth-token": "^2.4.4",
"@octokit/rest": "18.0.9",
"@octokit/auth-app": "^3.3.0",
"@octokit/auth-token": "^2.4.5",
"@octokit/rest": "^18.5.2",
"axios": "^0.21.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"fontsource-open-sans": "^3.1.5",
"ioredis": "^4.19.2",
"markdown-it": "^12.0.2",
"matrix-bot-sdk": "^0.5.8",
"matrix-widget-api": "^0.1.0-beta.10",
"micromatch": "^4.0.2",
"mime": "^2.4.6",
"mini.css": "^3.0.1",
"ioredis": "^4.26.0",
"markdown-it": "^12.0.4",
"matrix-bot-sdk": "^0.5.17",
"matrix-widget-api": "^0.1.0-beta.13",
"micromatch": "^4.0.4",
"mime": "^2.5.2",
"mocha": "^8.2.1",
"node-emoji": "^1.10.0",
"reflect-metadata": "^0.1.13",
"source-map-support": "^0.5.19",
"string-argv": "v0.3.1",
"uuid": "^8.3.1",
"string-argv": "^0.3.1",
"uuid": "^8.3.2",
"winston": "^3.3.3",
"yaml": "^2.0.0-1"
},
"devDependencies": {
"@prefresh/snowpack": "^2.2.0",
"@snowpack/plugin-typescript": "^1.1.1",
"@types/chai": "^4.2.14",
"@types/cors": "^2.8.9",
"@types/express": "^4.17.9",
"@types/ioredis": "^4.17.8",
"@types/markdown-it": "^10.0.3",
"@prefresh/snowpack": "^3.1.2",
"@snowpack/plugin-typescript": "^1.2.1",
"@fontsource/open-sans": "^4.2.2",
"@types/chai": "^4.2.16",
"@types/cors": "^2.8.10",
"@types/express": "^4.17.11",
"@types/ioredis": "^4.22.3",
"@types/markdown-it": "^12.0.1",
"@types/micromatch": "^4.0.1",
"@types/mime": "^2.0.3",
"@types/mocha": "^8.0.4",
"@types/mocha": "^8.2.2",
"@types/node": "^12",
"@types/node-emoji": "^1.8.1",
"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"autoprefixer": "^10.1.0",
"chai": "^4.2.0",
"eslint": "^7.14.0",
"eslint-plugin-mocha": "^8.0.0",
"preact": "^10.5.7",
"snowpack": "^2.18.3",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
"chai": "^4.3.4",
"eslint": "^7.24.0",
"eslint-plugin-mocha": "^8.1.0",
"preact": "^10.5.13",
"mini.css": "^3.0.1",
"snowpack": "^3.2.2",
"tailwind": "^4.0.0",
"ts-node": "^9.0.0",
"typescript": "^4.1.2"
"ts-node": "^9.1.1",
"typescript": "^4.2.4"
}
}

View File

@ -7,25 +7,12 @@ module.exports = {
'@prefresh/snowpack',
['@snowpack/plugin-typescript', '--project tsconfig.web.json'],
],
install: [
/* ... */
],
installOptions: {
packageOptions: {
installTypes: true,
polyfillNode: true,
},
devOptions: {
/* ... */
},
buildOptions: {
out: 'public'
/* ... */
},
proxy: {
/* ... */
},
alias: {
/* ... */
},
};

View File

@ -14,8 +14,12 @@ import { GitLabClient } from "./Gitlab/Client";
import { GetUserResponse } from "./Gitlab/Types";
import { GithubInstance } from "./Github/GithubInstance";
import { MatrixMessageContent } from "./MatrixEvent";
import { ProjectsListForUserResponseData, ProjectsListForRepoResponseData } from "@octokit/types";
import { BridgeRoomState, BridgeRoomStateGitHub } from "./Widgets/BridgeWidgetInterface";
import { Endpoints } from "@octokit/types";
import { ProjectsListResponseData } from "./Github/Types";
type ProjectsListForRepoResponseData = Endpoints["GET /repos/{owner}/{repo}/projects"]["response"];
type ProjectsListForUserResponseData = Endpoints["GET /users/{username}/projects"]["response"];
const md = new markdown();
@ -240,10 +244,11 @@ export class AdminRoom extends EventEmitter {
if (!username) {
const me = await octokit.users.getAuthenticated();
username = me.data.name;
// TODO: Fix
username = me.data.name!;
}
let res: ProjectsListForUserResponseData|ProjectsListForRepoResponseData;
let res: ProjectsListResponseData;
try {
if (repo) {
res = (await octokit.projects.listForRepo({
@ -259,7 +264,7 @@ export class AdminRoom extends EventEmitter {
return this.sendNotice(`Failed to fetch projects due to an error. See logs for details`);
}
const content = `Projects for ${username}:\n` + res.map(r => ` - ${FormatUtil.projectListing([r])}\n`).join("\n");
const content = `Projects for ${username}:\n${FormatUtil.projectListing(res)}\n`;
return this.botIntent.sendEvent(this.roomId,{
msgtype: "m.notice",
body: content,
@ -285,11 +290,11 @@ export class AdminRoom extends EventEmitter {
res = (await octokit.projects.listForRepo({
repo,
owner: org,
})).data;
}));
}
res = (await octokit.projects.listForOrg({
org,
})).data;
}));
} catch (ex) {
if (ex.status === 404) {
return this.sendNotice('Not found');
@ -298,7 +303,7 @@ export class AdminRoom extends EventEmitter {
return this.sendNotice(`Failed to fetch projects due to an error. See logs for details`);
}
const content = `Projects for ${org}:\n` + res.map(r => ` - ${FormatUtil.projectListing([r])}\n`).join("\n");
const content = `Projects for ${org}:\n` + res.data.map(r => ` - ${FormatUtil.projectListing([r])}\n`).join("\n");
return this.botIntent.sendEvent(this.roomId,{
msgtype: "m.notice",
body: content,

View File

@ -6,7 +6,7 @@ import { MatrixMessageContent, MatrixEvent } from "./MatrixEvent";
import LogWrapper from "./LogWrapper";
import axios from "axios";
import { FormatUtil } from "./FormatUtil";
import { IssuesGetCommentResponseData, ReposGetResponseData, IssuesGetResponseData } from "@octokit/types";
import { IssuesGetCommentResponseData, ReposGetResponseData, IssuesGetResponseData } from "./Github/Types"
import { IGitLabWebhookNoteEvent } from "./Gitlab/WebhookTypes";
const REGEX_MENTION = /(^|\s)(@[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38})(\s|$)/ig;
@ -59,7 +59,10 @@ export class CommentProcessor {
public async getEventBodyForGitHubComment(comment: IssuesGetCommentResponseData,
repo?: ReposGetResponseData,
issue?: IssuesGetResponseData): Promise<IMatrixCommentEvent> {
issue?: IssuesGetResponseData): Promise<IMatrixCommentEvent|undefined> {
if (!comment.body) {
return undefined;
}
let body = comment.body;
body = this.replaceMentions(body);
body = await this.replaceImages(body, true);

View File

@ -6,6 +6,7 @@ export function configKey(comment?: string, optional = false) {
return Reflect.metadata(configKeyMetadataKey, [comment, optional]);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getConfigKeyMetadata(target: any, propertyKey: string): [string, boolean] {
return Reflect.getMetadata(configKeyMetadataKey, target, propertyKey);
}

View File

@ -1,7 +1,6 @@
import { BridgeConfig } from "./Config";
import YAML from "yaml";
import { getConfigKeyMetadata } from "./Decorators";
import { Node, YAMLSeq } from "yaml/types";
import { Node, YAMLSeq, Document, stringify } from "yaml";
import { randomBytes } from "crypto";
const DefaultConfig = new BridgeConfig({
@ -61,13 +60,13 @@ const DefaultConfig = new BridgeConfig({
}
}, {});
function renderSection(doc: YAML.Document, obj: Record<string, unknown>, parentNode?: YAMLSeq) {
function renderSection(doc: Document, obj: Record<string, unknown>, parentNode?: YAMLSeq) {
const entries = Object.entries(obj);
entries.forEach(([key, value]) => {
let newNode: Node;
if (typeof value === "object") {
if (typeof value === "object" && !Array.isArray(value)) {
newNode = doc.createNode({});
renderSection(doc, value as any, newNode as YAMLSeq);
renderSection(doc, value as Record<string, unknown>, newNode as YAMLSeq);
} else {
newNode = doc.createNode(value);
}
@ -86,10 +85,9 @@ function renderSection(doc: YAML.Document, obj: Record<string, unknown>, parentN
}
function renderDefaultConfig() {
const doc = new YAML.Document({});
const doc = new Document({});
doc.commentBefore = ' This is an example configuration file';
// Needed because the entries syntax below would not work otherwise
//const typeLessDefaultConfig = DefaultConfig as any;
renderSection(doc, DefaultConfig as any);
return doc.toString();
}
@ -127,7 +125,7 @@ async function renderRegistrationFile(configPath?: string) {
rooms: [],
},
};
console.log(YAML.stringify(obj));
console.log(stringify(obj));
}

View File

@ -12,7 +12,7 @@ import { FormatUtil } from "../FormatUtil";
import { IGitHubWebhookEvent } from "../GithubWebhooks";
import axios from "axios";
import { GithubInstance } from "../Github/GithubInstance";
import { IssuesGetResponseData } from "@octokit/types";
import { IssuesGetResponseData } from "../Github/Types";
export interface GitHubIssueConnectionState {
org: string;
@ -168,8 +168,10 @@ export class GitHubIssueConnection implements IConnection {
avatarUrl: comment.user.avatar_url,
}, this.as);
const matrixEvent = await this.commentProcessor.getEventBodyForGitHubComment(comment, event.repository, event.issue);
await this.messageClient.sendMatrixMessage(this.roomId, matrixEvent, "m.room.message", commentIntent.userId);
// Comment body may be blank
if (matrixEvent) {
await this.messageClient.sendMatrixMessage(this.roomId, matrixEvent, "m.room.message", commentIntent.userId);
}
if (!updateState) {
return;
}
@ -193,8 +195,9 @@ export class GitHubIssueConnection implements IConnection {
if (this.state.comments_processed === -1) {
// This has a side effect of creating a profile for the user.
const creator = await getIntentForUser({
login: issue.data.user.login,
avatarUrl: issue.data.user.avatar_url
// TODO: Fix
login: issue.data.user?.login as string,
avatarUrl: issue.data.user?.avatar_url || undefined
}, this.as);
// We've not sent any messages into the room yet, let's do it!
if (issue.data.body) {
@ -232,11 +235,12 @@ export class GitHubIssueConnection implements IConnection {
if (this.state.state !== issue.data.state) {
if (issue.data.state === "closed") {
const closedUserId = this.as.getUserIdForSuffix(issue.data.closed_by.login);
// TODO: Fix
const closedUserId = this.as.getUserIdForSuffix(issue.data.closed_by?.login as string);
await this.messageClient.sendMatrixMessage(this.roomId, {
msgtype: "m.notice",
body: `closed the ${issue.data.pull_request ? "pull request" : "issue"} at ${issue.data.closed_at}`,
external_url: issue.data.closed_by.html_url,
external_url: issue.data.closed_by?.html_url,
}, "m.room.message", closedUserId);
}

View File

@ -1,7 +1,7 @@
import { IConnection } from "./IConnection";
import { Appservice } from "matrix-bot-sdk";
import LogWrapper from "../LogWrapper";
import { ProjectsGetResponseData } from "@octokit/types";
import { ProjectsGetResponseData } from "../Github/Types";
export interface GitHubProjectConnectionState {
// eslint-disable-next-line camelcase

View File

@ -12,7 +12,7 @@ import { FormatUtil } from "../FormatUtil";
import axios from "axios";
import { BotCommands, handleCommand, botCommand, compileBotCommands } from "../BotCommands";
import { IGitHubWebhookEvent } from "../GithubWebhooks";
import { ReposGetResponseData } from "@octokit/types";
import { ReposGetResponseData } from "../Github/Types";
const log = new LogWrapper("GitHubRepoConnection");
const md = new markdown();
@ -265,11 +265,13 @@ export class GitHubRepoConnection implements IConnection {
}
const orgRepoName = event.issue.repository_url.substr("https://api.github.com/repos/".length);
const content = `New issue created [${orgRepoName}#${event.issue.number}](${event.issue.html_url}): "${event.issue.title}"`;
const labelsHtml = event.issue.labels.map((label: {color: string, name: string, description: string}) =>
`<span title="${label.description}" data-mx-color="#CCCCCC" data-mx-bg-color="#${label.color}">${label.name}</span>`
const labelsHtml = event.issue.labels.map((label: {color?: string|null, name?: string, description?: string|null}|string) =>
typeof(label) === "string" ?
`<span>${label}</span>` :
`<span title="${label.description}" data-mx-color="#CCCCCC" data-mx-bg-color="#${label.color}">${label.name}</span>`
).join(" ") || "";
const labels = event.issue?.labels.map((label: {name: string}) =>
label.name
const labels = event.issue?.labels.map((label: {name?: string}|string) =>
typeof(label) === "string" ? label : label.name
).join(", ") || "";
await this.as.botIntent.sendEvent(this.roomId, {
msgtype: "m.notice",

View File

@ -1,7 +1,6 @@
import { IConnection } from "./IConnection";
import { Appservice } from "matrix-bot-sdk";
import { MatrixMessageContent, MatrixEvent } from "../MatrixEvent";
import markdown from "markdown-it";
import { UserTokenStore } from "../UserTokenStore";
import LogWrapper from "../LogWrapper";
import { CommentProcessor } from "../CommentProcessor";
@ -23,9 +22,6 @@ export interface GitLabIssueConnectionState {
}
const log = new LogWrapper("GitLabIssueConnection");
const md = new markdown();
md.render("foo");
// interface IQueryRoomOpts {
// as: Appservice;

View File

@ -1,4 +1,5 @@
import { IssuesGetCommentResponseData, IssuesGetResponseData, ProjectsListForOrgResponseData, ProjectsListForUserResponseData, ProjectsListForRepoResponseData } from "@octokit/types";
/* eslint-disable camelcase */
import { IssuesGetCommentResponseData, IssuesGetResponseData, ProjectsListResponseData } from './Github/Types';
interface IMinimalRepository {
id: number;
@ -12,8 +13,8 @@ export class FormatUtil {
return `${orgRepoName}#${issue.number}: ${issue.title}`;
}
public static formatRepoRoomName(repo: {full_name: string, description: string}) {
return `${repo.full_name}: ${repo.description}`;
public static formatRepoRoomName(repo: {full_name: string, description: string|null}) {
return repo.description ? `${repo.full_name}: ${repo.description}` : repo.full_name;
}
public static formatRoomTopic(repo: {state: string, html_url: string}) {
@ -61,7 +62,11 @@ export class FormatUtil {
};
}
public static projectListing(projectItem: ProjectsListForOrgResponseData|ProjectsListForUserResponseData|ProjectsListForRepoResponseData) {
return `${projectItem[0].name} (#${projectItem[0].number}) - Project ID: ${projectItem[0].id}`
public static projectListing(projects: ProjectsListResponseData): string {
let f = '';
for (const projectItem of projects) {
f += ` - ${projectItem.name} (#${projectItem.number}) - Project ID: ${projectItem.id}`;
}
return f;
}
}

View File

@ -1,5 +1,18 @@
import { IssuesGetResponseData, IssuesGetCommentResponseData, PullsListReviewsResponseData, ReposGetResponseData, PullsListRequestedReviewersResponseData } from "@octokit/types";
import { Endpoints } from "@octokit/types";
export type IssuesGetResponseData = Endpoints["GET /repos/{owner}/{repo}/issues/{issue_number}"]["response"]["data"];
export type IssuesGetCommentResponseData = Endpoints["GET /repos/{owner}/{repo}/issues/comments/{comment_id}"]["response"]["data"];
export type PullsListReviewsResponseData = Endpoints["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews"]["response"]["data"];
export type PullsListRequestedReviewersResponseData = Endpoints["GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers"]["response"]["data"];
export type ReposGetResponseData = Endpoints["GET /repos/{owner}/{repo}"]["response"]["data"];
export type ProjectsGetResponseData = Endpoints["GET /projects/{project_id}"]["response"]["data"];
export type ProjectsListForTeamsResponseData = Endpoints["GET /teams/{team_id}/projects"]["response"]["data"];
export type ProjectsListForRepoResponseData = Endpoints["GET /repos/{owner}/{repo}/projects"]["response"]["data"];
export type ProjectsListForUserResponseData = Endpoints["GET /users/{username}/projects"]["response"]["data"];
export type ProjectsListResponseData = ProjectsListForTeamsResponseData|ProjectsListForRepoResponseData|ProjectsListForUserResponseData;
export type IssuesListAssigneesResponseData = Endpoints["GET /repos/{owner}/{repo}/issues"]["response"]["data"];
export type PullsGetResponseData = Endpoints["GET /repos/{owner}/{repo}/pulls"]["response"]["data"];
export type PullGetResponseData = Endpoints["GET /repos/{owner}/{repo}/pulls/{pull_number}"]["response"]["data"];
/* eslint-disable camelcase */
export interface GitHubUserNotification {
id: string;

View File

@ -1,5 +1,4 @@
import { Appservice, IAppserviceRegistration, RichRepliesPreprocessor, IRichReplyMetadata } from "matrix-bot-sdk";
import { ProjectsGetResponseData } from "@octokit/types";
import { BridgeConfig, GitLabInstance } from "./Config/Config";
import { IGitHubWebhookEvent, IOAuthRequest, IOAuthTokens, NotificationsEnableEvent,
NotificationsDisableEvent } from "./GithubWebhooks";
@ -27,6 +26,7 @@ import { GitLabIssueConnection } from "./Connections/GitlabIssue";
import { GetIssueResponse, GetIssueOpts } from "./Gitlab/Types"
import { GitLabClient } from "./Gitlab/Client";
import { BridgeWidgetApi } from "./Widgets/BridgeWidgetApi";
import { ProjectsGetResponseData } from "./Github/Types";
const log = new LogWrapper("GithubBridge");
@ -220,15 +220,19 @@ export class GithubBridge {
if (!data.repository || !data.issue) {
throw Error("Malformed webhook event, missing repository or issue");
}
if (!data.repository.owner?.login) {
throw Error('Cannot get connection for ownerless issue');
}
return {
owner: data.repository.owner?.login,
repository: data.repository,
issue: data.issue,
};
}
this.queue.on<IGitHubWebhookEvent>("comment.created", async ({ data }) => {
const { repository, issue } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(repository.owner.login, repository.name, issue.number);
const { repository, issue, owner } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
connections.map(async (c) => {
try {
if (c instanceof GitHubIssueConnection)
@ -240,8 +244,8 @@ export class GithubBridge {
});
this.queue.on<IGitHubWebhookEvent>("issue.opened", async ({ data }) => {
const { repository } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubRepo(repository.owner.login, repository.name);
const { repository, owner } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubRepo(owner, repository.name);
connections.map(async (c) => {
try {
await c.onIssueCreated(data);
@ -252,8 +256,8 @@ export class GithubBridge {
});
this.queue.on<IGitHubWebhookEvent>("issue.edited", async ({ data }) => {
const { repository, issue } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(repository.owner.login, repository.name, issue.number);
const { repository, issue, owner } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
connections.map(async (c) => {
try {
if (c instanceof GitHubIssueConnection)
@ -265,8 +269,8 @@ export class GithubBridge {
});
this.queue.on<IGitHubWebhookEvent>("issue.closed", async ({ data }) => {
const { repository, issue } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(repository.owner.login, repository.name, issue.number);
const { repository, issue, owner } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
connections.map(async (c) => {
try {
if (c instanceof GitHubIssueConnection)
@ -278,8 +282,8 @@ export class GithubBridge {
});
this.queue.on<IGitHubWebhookEvent>("issue.reopened", async ({ data }) => {
const { repository, issue } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(repository.owner.login, repository.name, issue.number);
const { repository, issue, owner } = validateRepoIssue(data);
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
connections.map(async (c) => {
try {
if (c instanceof GitHubIssueConnection)
@ -413,7 +417,7 @@ export class GithubBridge {
if (connections.length === 0) {
// TODO: Refactor this to be a connection
try {
const accountData = await this.as.botIntent.underlyingClient.getRoomAccountData(
const accountData = await this.as.botIntent.underlyingClient.getRoomAccountData<AdminAccountData>(
BRIDGE_ROOM_TYPE, roomId,
);
const adminRoom = await this.setupAdminRoom(roomId, accountData);
@ -461,9 +465,9 @@ export class GithubBridge {
log.info(`Got message roomId=${roomId} from=${event.sender}`);
log.debug(event);
if (this.adminRooms.has(roomId)) {
const room = this.adminRooms.get(roomId)!;
if (room.userId !== event.sender) {
const adminRoom = this.adminRooms.get(roomId);
if (adminRoom) {
if (adminRoom.userId !== event.sender) {
return;
}
@ -472,7 +476,7 @@ export class GithubBridge {
if (processedReply) {
const metadata: IRichReplyMetadata = processedReply.mx_richreply;
log.info(`Handling reply to ${metadata.parentEventId} for ${room.userId}`);
log.info(`Handling reply to ${metadata.parentEventId} for ${adminRoom.userId}`);
// This might be a reply to a notification
try {
const ev = metadata.realEvent;
@ -490,15 +494,14 @@ export class GithubBridge {
log.info("Missing parts!:", splitParts, issueNumber);
}
} catch (ex) {
await room.sendNotice("Failed to handle repy. You may not be authenticated to do that.");
await adminRoom.sendNotice("Failed to handle repy. You may not be authenticated to do that.");
log.error("Reply event could not be handled:", ex);
}
return;
}
const command = event.content.body;
const adminRoom = this.adminRooms.get(roomId);
if (command && adminRoom) {
if (command) {
await adminRoom.handleCommand(event.event_id, command);
}
}

View File

@ -1,7 +1,6 @@
import { BridgeConfig } from "./Config/Config";
import { Application, default as express, Request, Response } from "express";
import { createHmac } from "crypto";
import { IssuesGetResponseData, IssuesGetCommentResponseData, ReposGetResponseData } from "@octokit/types";
import { EventEmitter } from "events";
import { MessageQueue, createMessageQueue, MessageQueueMessage } from "./MessageQueue/MessageQueue";
import LogWrapper from "./LogWrapper";
@ -10,6 +9,7 @@ import { Server } from "http";
import axios from "axios";
import { UserNotificationWatcher } from "./Notifications/UserNotificationWatcher";
import { IGitLabWebhookEvent } from "./Gitlab/WebhookTypes";
import { IssuesGetCommentResponseData, IssuesGetResponseData, ReposGetResponseData } from "./Github/Types";
const log = new LogWrapper("GithubWebhooks");
@ -34,7 +34,9 @@ export interface IOAuthRequest {
}
export interface IOAuthTokens {
// eslint-disable-next-line camelcase
access_token: string;
// eslint-disable-next-line camelcase
token_type: string;
state: string;
}
@ -181,6 +183,7 @@ export class GithubWebhooks extends EventEmitter {
redirect_uri: this.config.github.oauth.redirect_uri,
state: req.query.state as string,
})}`);
// eslint-disable-next-line camelcase
const result = qs.parse(accessTokenRes.data) as { access_token: string, token_type: string };
await this.queue.push<IOAuthTokens>({
eventName: "oauth.tokens",

View File

@ -2,9 +2,8 @@ import { LogService } from "matrix-bot-sdk";
import util from "util";
import winston from "winston";
// Logs contain unknowns, ignore this.
// tslint:disable: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type MsgType = string|Error|any|{error?: string};
export default class LogWrapper {
public static configureLogging(level: string) {
@ -24,7 +23,7 @@ export default class LogWrapper {
}),
],
});
const getMessageString = (...messageOrObject: any[]) => {
const getMessageString = (messageOrObject: MsgType[]) => {
messageOrObject = messageOrObject.flat();
const messageParts: string[] = [];
messageOrObject.forEach((obj) => {
@ -37,7 +36,7 @@ export default class LogWrapper {
return messageParts.join(" ");
};
LogService.setLogger({
info: (module: string, ...messageOrObject: any[]) => {
info: (module: string, ...messageOrObject: MsgType[]) => {
// These are noisy, redirect to debug.
if (module.startsWith("MatrixLiteClient")) {
log.debug(getMessageString(messageOrObject), { module });
@ -45,19 +44,22 @@ export default class LogWrapper {
}
log.info(getMessageString(messageOrObject), { module });
},
warn: (module: string, ...messageOrObject: any[]) => {
warn: (module: string, ...messageOrObject: MsgType[]) => {
log.warn(getMessageString(messageOrObject), { module });
},
error: (module: string, ...messageOrObject: any[]) => {
if (messageOrObject[0]?.error === "Room account data not found") {
error: (module: string, ...messageOrObject: MsgType[]) => {
if (typeof messageOrObject[0] === "object" && messageOrObject[0].error === "Room account data not found") {
log.debug(getMessageString(messageOrObject), { module });
return; // This is just noise :|
}
log.error(getMessageString(messageOrObject), { module });
},
debug: (module: string, ...messageOrObject: any[]) => {
debug: (module: string, ...messageOrObject: MsgType[]) => {
log.debug(getMessageString(messageOrObject), { module });
},
trace: (module: string, ...messageOrObject: MsgType[]) => {
log.verbose(getMessageString(messageOrObject), { module });
},
});
LogService.info("LogWrapper", "Reconfigured logging");
}
@ -69,7 +71,7 @@ export default class LogWrapper {
* @param {string} module The module being logged
* @param {*[]} messageOrObject The data to log
*/
public debug(...messageOrObject: any[]) {
public debug(...messageOrObject: MsgType[]) {
LogService.debug(this.module, ...messageOrObject);
}
@ -77,7 +79,7 @@ export default class LogWrapper {
* Logs to the ERROR channel
* @param {*[]} messageOrObject The data to log
*/
public error(...messageOrObject: any[]) {
public error(...messageOrObject: MsgType[]) {
LogService.error(this.module, ...messageOrObject);
}
@ -85,7 +87,7 @@ export default class LogWrapper {
* Logs to the INFO channel
* @param {*[]} messageOrObject The data to log
*/
public info(...messageOrObject: any[]) {
public info(...messageOrObject: MsgType[]) {
LogService.info(this.module, ...messageOrObject);
}
@ -93,7 +95,7 @@ export default class LogWrapper {
* Logs to the WARN channel
* @param {*[]} messageOrObject The data to log
*/
public warn(...messageOrObject: any[]) {
public warn(...messageOrObject: MsgType[]) {
LogService.warn(this.module, ...messageOrObject);
}
}

View File

@ -106,6 +106,10 @@ export class GitHubWatcher extends EventEmitter implements NotificationWatcherTa
log.warn("review_requested was missing subject.url_data.number");
continue;
}
if (!rawEvent.repository.owner) {
log.warn("review_requested was missing repository.owner");
continue;
}
rawEvent.subject.requested_reviewers = (await this.octoKit.pulls.listRequestedReviewers({
pull_number: rawEvent.subject.url_data.number,
owner: rawEvent.repository.owner.login,

View File

@ -5,15 +5,17 @@ import LogWrapper from "./LogWrapper";
import { AdminRoom } from "./AdminRoom";
import markdown from "markdown-it";
import { FormatUtil } from "./FormatUtil";
import { IssuesListAssigneesResponseData, PullsGetResponseData, IssuesGetResponseData, PullsListRequestedReviewersResponseData, PullsListReviewsResponseData, IssuesGetCommentResponseData } from "@octokit/types";
import { PullGetResponseData, IssuesGetResponseData, PullsListRequestedReviewersResponseData, PullsListReviewsResponseData, IssuesGetCommentResponseData } from "./Github/Types";
import { GitHubUserNotification } from "./Github/Types";
import { components } from "@octokit/openapi-types/dist-types/generated/types";
const log = new LogWrapper("GithubBridge");
const md = new markdown();
export interface IssueDiff {
state: null|string;
assignee: null|IssuesListAssigneesResponseData;
assignee: null|(components["schemas"]["simple-user"][]);
title: null|string;
merged: boolean;
mergedBy: null|{
@ -34,7 +36,7 @@ export interface CachedReviewData {
reviews: PullsListReviewsResponseData;
}
type PROrIssue = IssuesGetResponseData|PullsGetResponseData;
type PROrIssue = IssuesGetResponseData|PullGetResponseData;
export class NotificationProcessor {
@ -66,12 +68,13 @@ export class NotificationProcessor {
plain += `\n\n Title changed to: ${diff.title}`;
}
if (diff.assignee) {
plain += `\n\n Assigned to: ${diff.assignee[0].login}`;
plain += `\n\n Assigned to: ${diff.assignee.map(l => l?.login).join(", ")}`;
}
}
if (newComment) {
const comment = notif.subject.latest_comment_url_data as IssuesGetCommentResponseData;
plain += `\n\n ${NotificationProcessor.formatUser(comment.user)}:\n\n > ${comment.body}`;
const user = comment.user ? NotificationProcessor.formatUser(comment.user) : 'user';
plain += `\n\n ${user}:\n\n > ${comment.body}`;
}
return {
plain,
@ -187,9 +190,12 @@ export class NotificationProcessor {
private diffIssueChanges(curr: PROrIssue, prev: PROrIssue): IssueDiff {
let merged = false;
let mergedBy = null;
if ((curr as PullsGetResponseData).merged !== (prev as PullsGetResponseData).merged) {
if ((curr as PullGetResponseData).merged !== (prev as PullGetResponseData).merged) {
merged = true;
mergedBy = (curr as PullsGetResponseData).merged_by;
mergedBy = (curr as PullGetResponseData).merged_by;
}
if (!curr.user) {
throw Error('No user for issue');
}
const diff: IssueDiff = {
state: curr.state === prev.state ? null : curr.state,
@ -217,7 +223,7 @@ export class NotificationProcessor {
(await this.storage.getLastNotifCommentUrl(notif.repository.full_name, issueNumber, roomId));
const formatted = NotificationProcessor.formatNotification(notif, diff, newComment);
let body: any = {
let body = {
msgtype: "m.text",
body: formatted.plain,
formatted_body: formatted.html,

View File

@ -1,6 +1,6 @@
import { MemoryStorageProvider as MSP } from "matrix-bot-sdk";
import { IStorageProvider } from "./StorageProvider";
import { IssuesGetResponseData } from "@octokit/types";
import { IssuesGetResponseData } from "../Github/Types";
export class MemoryStorageProvider extends MSP implements IStorageProvider {
private issues: Map<string, IssuesGetResponseData> = new Map();

View File

@ -1,4 +1,4 @@
import { IssuesGetResponseData } from "@octokit/types";
import { IssuesGetResponseData } from "../Github/Types";
import { Redis, default as redis } from "ioredis";
import LogWrapper from "../LogWrapper";

View File

@ -1,5 +1,5 @@
import { IAppserviceStorageProvider } from "matrix-bot-sdk";
import { IssuesGetResponseData } from "@octokit/types";
import { IssuesGetResponseData } from "../Github/Types";
export interface IStorageProvider extends IAppserviceStorageProvider {
setGithubIssue(repo: string, issueNumber: string, data: IssuesGetResponseData, scope?: string): Promise<void>;

View File

@ -46,12 +46,14 @@ export class UserTokenStore {
if (existingToken) {
return existingToken;
}
let obj;
try {
let obj;
if (type === "github") {
obj = await this.intent.underlyingClient.getAccountData(key);
obj = await this.intent.underlyingClient.getAccountData<{encrypted: string}>(key);
} else if (type === "gitlab") {
obj = await this.intent.underlyingClient.getAccountData(key);
obj = await this.intent.underlyingClient.getAccountData<{encrypted: string}>(key);
} else {
throw Error('Unknown type');
}
const encryptedTextB64 = obj.encrypted;
const encryptedText = Buffer.from(encryptedTextB64, "base64");

View File

@ -2,7 +2,7 @@ import { h, render } from 'preact';
import 'preact/devtools';
import App from './App';
import "./styling.css";
import "fontsource-open-sans/files/open-sans-latin-400-normal.woff2";
import "@fontsource/open-sans/files/open-sans-latin-400-normal.woff2";
const root = document.getElementsByTagName('main')[0];

View File

@ -1,5 +1,5 @@
@import "fontsource-open-sans/400-normal.css";
@import "../node_modules/@fontsource/open-sans/400.css";
@import "mini.css";
body {

3085
yarn.lock

File diff suppressed because it is too large Load Diff