Skip to content

Commit

Permalink
Move probot handlers (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludeeus authored Sep 21, 2022
1 parent bb9a8fe commit a6bb619
Show file tree
Hide file tree
Showing 46 changed files with 2,281 additions and 95 deletions.
33 changes: 32 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,40 @@ jobs:
- name: Run yarn lint
run: yarn lint

test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.2

- name: Use Node.js ${{ env.node-NODE_VERSION }}
uses: actions/setup-node@v3.4.1
with:
node-version: ${{ env.node-NODE_VERSION }}

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"

- name: Check yarn cache
uses: actions/cache@v3.0.7
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --immutable

- name: Run tests
run: yarn run test

build-container:
name: Build container
needs: lint
needs: test
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
Expand Down
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"start:bots": "nest start bots --watch",
"format": "prettier --write \"services/**/*.ts\" \"libs/**/*.ts\"",
"lint": "eslint \"{src,services,libs,test}/**/*.ts\" --fix",
"prebuild": "rimraf dist"
"prebuild": "rimraf dist",
"test": "ts-mocha --recursive --timeout 10000 tests/**/*.spec.ts",
"test-watch": "ts-mocha --recursive --timeout 10000 --watch tests/**/*.spec.ts"
},
"dependencies": {
"@dev-thought/nestjs-github-webhooks": "^1.0.0",
Expand All @@ -42,6 +44,7 @@
"@sentry/node": "^6.19.7",
"apollo-server-express": "^3.6.7",
"aws-sdk": "^2.1211.0",
"codeowners-utils": "^1.0.2",
"convict": "^6.2.3",
"discord.js": "^14.3.0",
"find-up": "^4.0.0",
Expand All @@ -66,10 +69,13 @@
"eslint": "8.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"mocha": "^10.0.0",
"prettier": "^2.6.2",
"sinon": "^14.0.0",
"source-map-support": "^0.5.21",
"ts-jest": "27.1.4",
"ts-loader": "^9.3.0",
"ts-mocha": "^10.0.0",
"ts-node": "^10.7.0",
"tsconfig-paths": "^3.14.1",
"typescript": "^4.6.4"
Expand Down Expand Up @@ -102,4 +108,4 @@
"@lib/sentry": "<rootDir>/libs/sentry/src"
}
}
}
}
6 changes: 3 additions & 3 deletions services/bots/src/cla-sign/cla-sign.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { ServiceError } from '@lib/common';
import { ClaIssueLabel } from '@lib/common/github';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Octokit } from '@octokit/rest';
import { DynamoDB } from 'aws-sdk';
import { GithubClient } from '../github-webhook/github-webhook.model';

@Injectable()
export class ClaSignService {
private githubApiClient: Octokit;
private githubApiClient: GithubClient;
private ddbClient: DynamoDB;
private signersTableName: string;
private pendingSignersTableName: string;

constructor(configService: ConfigService) {
this.githubApiClient = new Octokit({ auth: configService.get('github.token') });
this.githubApiClient = new GithubClient({ auth: configService.get('github.token') });
this.ddbClient = new DynamoDB({ region: configService.get('dynamodb.cla.region') });

this.signersTableName = configService.get('dynamodb.cla.signersTable');
Expand Down
101 changes: 100 additions & 1 deletion services/bots/src/github-webhook/github-webhook.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,106 @@ import { RestEndpointMethodTypes } from '@octokit/rest';
import { EventPayloadMap } from '@octokit/webhooks-types';
import { BaseWebhookHandler } from './handlers/base';

export const HOME_ASSISTANT_ORG = 'home-assistant';

export const WEBHOOK_HANDLERS: BaseWebhookHandler[] = [];

export type PullRequestEventData = EventPayloadMap['pull_request'];
export type ListCommitResponse = RestEndpointMethodTypes['pulls']['listCommits']['response'];
export type IssuesEventData = EventPayloadMap['issues'];
export type ListPullRequestFiles =
RestEndpointMethodTypes['pulls']['listFiles']['response']['data'];
export type GetPullRequestParams = RestEndpointMethodTypes['pulls']['get']['parameters'];
export type GetPullRequestResponse = RestEndpointMethodTypes['pulls']['get']['response']['data'];
export type GetIssueParams = RestEndpointMethodTypes['issues']['get']['parameters'];
export type GetIssueResponse = RestEndpointMethodTypes['issues']['get']['response']['data'];

export enum Repository {
BRANDS = 'brands',
CORE = 'core',
DEVELOPERS_HOME_ASSISTANT = 'developers.home-assistant',
HOME_ASSISTANT_IO = 'home-assistant.io',
}

export const entityComponents = new Set([
'air_quality',
'alarm_control_panel',
'automation',
'binary_sensor',
'calendar',
'camera',
'climate',
'cover',
'device_tracker',
'fan',
'geo_location',
'image_processing',
'light',
'lock',
'mailbox',
'media_player',
'notify',
'remote',
'scene',
'sensor',
'switch',
'tts',
'vacuum',
'water_heater',
'weather',
]);

export const coreComponents = new Set([
...entityComponents,
'alexa',
'api',
'auth',
'cloud',
'config',
'configurator',
'conversation',
'counter',
'default_config',
'demo',
'discovery',
'ffmpeg',
'frontend',
'google_assistant',
'group',
'hassio',
'homeassistant',
'history',
'http',
'input_boolean',
'input_datetime',
'input_number',
'input_select',
'input_text',
'introduction',
'ios',
'logbook',
'logger',
'lovelace',
'map',
'mobile_app',
'mqtt',
'onboarding',
'panel_custom',
'panel_iframe',
'persistent_notification',
'person',
'recorder',
'script',
'scene',
'shell_command',
'shopping_list',
'stream',
'sun',
'system_health',
'system_log',
'timer',
'updater',
'webhook',
'weblink',
'websocket_api',
'zone',
]);
7 changes: 2 additions & 5 deletions services/bots/src/github-webhook/github-webhook.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@ import { Body, Controller, Post, UseGuards, Headers } from '@nestjs/common';
import { GithubWebhookService } from './github-webhook.service';

import { GithubGuard, GithubWebhookEvents } from '@dev-thought/nestjs-github-webhooks';
import { WebhookContext } from './github-webhook.model';

@Controller('/github-webhook')
@UseGuards(GithubGuard)
export class GithubWebhookController {
constructor(private readonly GithubWebhookService: GithubWebhookService) {}
constructor(private readonly githubWebhookService: GithubWebhookService) {}

@Post()
@GithubWebhookEvents([])
async webhook(
@Headers() headers: Record<string, any>,
@Body() payload: Record<string, any>,
): Promise<void> {
await this.GithubWebhookService.handleWebhook(
new WebhookContext({ eventType: `${headers['x-github-event']}.${payload.action}`, payload }),
);
await this.githubWebhookService.handleWebhook(headers, payload);
}
}
74 changes: 61 additions & 13 deletions services/bots/src/github-webhook/github-webhook.model.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,94 @@
interface WebhookContextParams {
payload: Record<string, any>;
import { Octokit } from '@octokit/rest';
import {
GetIssueParams,
GetIssueResponse,
GetPullRequestParams,
GetPullRequestResponse,
ListPullRequestFiles,
} from './github-webhook.const';

export class GithubClient extends Octokit {}

interface WebhookContextParams<E> {
github: GithubClient;
payload: E;
eventType: string;
}

export class WebhookContext {
export class WebhookContext<E> {
public github: GithubClient;
public eventType: string;
public payload: Record<string, any>;
public scheduledComments: { context: string; comment: string }[] = [];
public payload: E;
public scheduledComments: { handler: string; comment: string }[] = [];
public scheduledlabels: string[] = [];

constructor(params: WebhookContextParams) {
public _prFilesCache?: ListPullRequestFiles;
private _issueRequestCache: { [key: string]: GetIssueResponse } = {};
private _pullRequestCache: { [key: string]: GetPullRequestResponse } = {};

constructor(params: WebhookContextParams<E>) {
this.github = params.github;
this.eventType = params.eventType;
this.payload = params.payload;
}

public repo<T>(data?: T) {
public get senderIsBot(): boolean {
return (
(this.payload as any).sender.type === 'Bot' ||
(this.payload as any).sender.login === 'homeassistant'
);
}

public repo<T>(data?: T): { owner: string; repo: string } & T {
return {
owner: this.payload.repository.owner.login,
repo: this.payload.repository.name,
owner: (this.payload as any).repository.owner.login,
repo: (this.payload as any).repository.name,
...data,
};
}

public issue<T>(data?: T) {
return {
issue_number: (this.payload.issue || this.payload.pull_request || this.payload).number,
issue_number: ((this.payload as any).issue?.number ||
(this.payload as any).pull_request?.number ||
(this.payload as any)?.number) as number,
...this.repo(data),
};
}

public pullRequest<T>(data?: T) {
return {
pull_number: (this.payload.issue || this.payload.pull_request || this.payload).number,
pull_number: (
(this.payload as any).issue ||
(this.payload as any).pull_request ||
this.payload
).number as number,
...this.repo(data),
};
}

public scheduleIssueComment(context: string, comment: string): void {
this.scheduledComments.push({ context, comment });
public scheduleIssueComment(handler: string, comment: string): void {
this.scheduledComments.push({ handler, comment });
}

public scheduleIssueLabel(label: string): void {
this.scheduledlabels.push(label);
}

public async fetchIssueWithCache(params: GetIssueParams): Promise<GetIssueResponse> {
const key = `${params.owner}/${params.repo}/${params.pull_number}`;
if (!(key in this._issueRequestCache)) {
this._issueRequestCache[key] = (await this.github.issues.get(params)).data;
}
return this._issueRequestCache[key];
}
public async fetchPullRequestWithCache(
params: GetPullRequestParams,
): Promise<GetPullRequestResponse> {
const key = `${params.owner}/${params.repo}/${params.pull_number}`;
if (!(key in this._pullRequestCache)) {
this._pullRequestCache[key] = (await this.github.pulls.get(params)).data;
}
return this._pullRequestCache[key];
}
}
31 changes: 30 additions & 1 deletion services/bots/src/github-webhook/github-webhook.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,39 @@ import { GithubWebhooksModule } from '@dev-thought/nestjs-github-webhooks';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AppConfig } from '../config';
import { GithubWebhookController } from './github-webhook.controller';
import { BranchLabels } from './handlers/branch_labels';
import { CodeOwnersMention } from './handlers/code_owners_mention';
import { DependencyBump } from './handlers/dependency_bump';
import { DocsMissing } from './handlers/docs_missing';
import { DocsParenting } from './handlers/docs_parenting';
import { DocsTargetBranch } from './handlers/docs_target_branch';
import { Hacktoberfest } from './handlers/hacktoberfest';
import { IssueLinks } from './handlers/issue_links';
import { LabelBot } from './handlers/label_bot/handler';
import { LabelCleaner } from './handlers/label_cleaner';
import { ReviewEnforcer } from './handlers/review_enforcer';
import { SetDocumentationSection } from './handlers/set_documentation_section';
import { SetIntegration } from './handlers/set_integration';
import { ValidateCla } from './handlers/validate-cla';

@Module({
providers: [GithubWebhookService, ValidateCla],
providers: [
BranchLabels,
CodeOwnersMention,
DependencyBump,
DocsMissing,
DocsParenting,
DocsTargetBranch,
GithubWebhookService,
Hacktoberfest,
IssueLinks,
LabelBot,
LabelCleaner,
ReviewEnforcer,
SetDocumentationSection,
SetIntegration,
ValidateCla,
],
imports: [
GithubWebhooksModule.forRootAsync({
imports: [ConfigModule],
Expand Down
Loading

0 comments on commit a6bb619

Please sign in to comment.