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

๐Ÿ“ฆ upgrade packages & change to biome #86

Merged
merged 1 commit into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,5 @@ jobs:
run: bun install
- name: Check Type
run: bun tsc
- name: Check format
run: bun format
- name: Check lint
run: bun lint
- name: Check format & lint
run: bun check
8 changes: 0 additions & 8 deletions .prettierrc

This file was deleted.

8 changes: 8 additions & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"code_actions_on_format": {
"source.fixAll.biome": true,
"source.organizeImports.biome": true
},
"formatter": { "language_server": { "name": "biome" } },
"lsp": { "biome": { "settings": { "require_config_file": true } } }
}
49 changes: 49 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"linter": {
"rules": {
"all": true,
"correctness": {
"noUndeclaredDependencies": "off",
"useImportExtensions": "off"
},
"performance": {
"noAccumulatingSpread": "off"
},
"suspicious": {
"noConsole": {
"options": {
"allow": ["error"]
},
"level": "error"
},
"noReactSpecificProps": "off"
},
"style": {
"useNamingConvention": "off",
"useBlockStatements": "off",
"useDefaultSwitchClause": "off",
"useFilenamingConvention": "off"
}
}
},
"files": {
"ignore": ["*.js"]
},
"formatter": {
"indentStyle": "space",
"lineWidth": 80,
"formatWithErrors": true
},
"javascript": {
"formatter": {
"quoteStyle": "single"
},
"globals": ["Bun"]
}
}
418 changes: 418 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

Binary file removed bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[install]
exact = true
3 changes: 0 additions & 3 deletions eslint.config.js

This file was deleted.

21 changes: 10 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,19 @@
"start:server": "bun src/server.ts",
"deploy:server": "./scripts/deploy.sh",
"send:weekly-dashboard": "bun src/weekly-dashboard.ts",
"lint": "eslint ./src",
"format": "prettier . --check"
"check": "biome check .",
"fix": "biome check --fix ."
},
"dependencies": {
"octokit": "4.0.2",
"openai": "4.76.0"
"octokit": "4.1.0",
"openai": "4.80.1"
},
"devDependencies": {
"@types/bun": "1.1.14",
"@woohm402/eslint-config-base": "0.12.0",
"eslint": "9.16.0",
"knip": "5.39.2",
"prettier": "3.4.2",
"typescript": "5.7.2"
"@biomejs/biome": "1.9.4",
"@types/bun": "1.2.0",
"eslint": "9.19.0",
"knip": "5.43.5",
"typescript": "5.7.3"
},
"packageManager": "bun@1.1.33"
"packageManager": "bun@1.2.0"
}
2 changes: 1 addition & 1 deletion src/controllers/DeployWebhookConrtoller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export type DeployWebhookController = {
handle: (body: unknown) => Promise<unknown>;
handle: (body: unknown) => unknown;
};
5 changes: 4 additions & 1 deletion src/entities/Score.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const getScore = ({ pullRequestCount, commentCount }: { pullRequestCount: number; commentCount: number }) => {
export const getScore = ({
pullRequestCount,
commentCount,
}: { pullRequestCount: number; commentCount: number }) => {
return pullRequestCount * 5 + commentCount;
};
15 changes: 13 additions & 2 deletions src/entities/Slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ type UserId = string;

export type SlackEvent =
| { type: 'channel_archive'; channel: ChannelId; user: UserId }
| { type: 'channel_created'; channel: { id: ChannelId; name: string; created: number; creator: UserId } }
| { type: 'channel_rename'; channel: { id: ChannelId; name: string; created: number } }
| {
type: 'channel_created';
channel: {
id: ChannelId;
name: string;
created: number;
creator: UserId;
};
}
| {
type: 'channel_rename';
channel: { id: ChannelId; name: string; created: number };
}
| { type: 'channel_unarchive'; channel: ChannelId; user: UserId };
23 changes: 17 additions & 6 deletions src/infrastructures/implementGitHubDeployWebhookController.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { type DeployWebhookController } from '../controllers/DeployWebhookConrtoller';
import { type GithubDeploymentService } from '../services/GithubDeploymentService';
import type { DeployWebhookController } from '../controllers/DeployWebhookConrtoller';
import type { GithubDeploymentService } from '../services/GithubDeploymentService';

type ReleaseBody = {
release: { author: { login: string }; body: string; tag_name: string; html_url: string };
release: {
author: { login: string };
body: string;
tag_name: string;
html_url: string;
};
repository: { name: string };
};

type WorkflowRunBody = {
workflow_run: { name: string; head_branch: string; id: number; html_url: string };
workflow_run: {
name: string;
head_branch: string;
id: number;
html_url: string;
};
repository: { name: string };
};

Expand All @@ -17,8 +27,9 @@ export const implementGitHubDeployWebhookController = ({
deploymentService: GithubDeploymentService;
}): DeployWebhookController => {
return {
handle: async (body) => {
if (body === null || typeof body !== 'object' || !('action' in body)) throw new Error('400');
handle: (body) => {
if (body === null || typeof body !== 'object' || !('action' in body))
throw new Error('400');

if ('release' in body && body.action === 'released') {
const releaseBody = body as unknown as ReleaseBody;
Expand Down
12 changes: 9 additions & 3 deletions src/infrastructures/implementGithubOctokitRepository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Octokit } from 'octokit';

import { implementDashboardService } from '../services/DashboardService';
import type { implementDashboardService } from '../services/DashboardService';

export const implementGithubOctokitRepository = ({
githubAuthToken,
Expand All @@ -17,7 +17,9 @@ export const implementGithubOctokitRepository = ({
sort: options?.sort,
per_page: options?.perPage,
})
.then((res) => res.data.map((d) => ({ name: d.name, webUrl: d.html_url }))),
.then((res) =>
res.data.map((d) => ({ name: d.name, webUrl: d.html_url })),
),

listRepositoryPullRequests: ({ organization, repository, options }) =>
octokit.rest.pulls
Expand Down Expand Up @@ -47,7 +49,11 @@ export const implementGithubOctokitRepository = ({
per_page: options?.perPage,
})
.then((res) =>
res.data.map((d) => ({ body: d.body, userGithubUsername: d.user.login, createdAt: new Date(d.created_at) })),
res.data.map((d) => ({
body: d.body,
userGithubUsername: d.user.login,
createdAt: new Date(d.created_at),
})),
),
};
};
19 changes: 14 additions & 5 deletions src/infrastructures/implementMemberWaffleDotComRepository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Member } from '../entities/Member';
import type { Member } from '../entities/Member';

/*
* API
Expand All @@ -9,12 +9,21 @@ export const implementMemberWaffleDotComRepository = (): {
} => {
return {
getAllMembers: async () => {
const users = await fetch('https://wadot-api.wafflestudio.com/api/v1/users', {
method: 'GET',
}).then((res) => res.json() as Promise<{ github_id: string; slack_id: string }[]>);
const users = await fetch(
'https://wadot-api.wafflestudio.com/api/v1/users',
{
method: 'GET',
},
).then(
(res) =>
res.json() as Promise<{ github_id: string; slack_id: string }[]>,
);

return {
members: users.map((user) => ({ slackUserId: user.slack_id, githubUsername: user.github_id })),
members: users.map((user) => ({
slackUserId: user.slack_id,
githubUsername: user.github_id,
})),
};
},
};
Expand Down
6 changes: 4 additions & 2 deletions src/infrastructures/implementOpenAiSummarizeRepository.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import OpenAI from 'openai';

import { implementDeploymentService } from '../services/GithubDeploymentService';
import type { implementDeploymentService } from '../services/GithubDeploymentService';

export const implementOpenAiSummarizeRepository = ({
openaiApiKey,
}: {
openaiApiKey: string;
}): Parameters<typeof implementDeploymentService>[0]['summarizeLLMRepository'] => {
}): Parameters<
typeof implementDeploymentService
>[0]['summarizeLLMRepository'] => {
return {
summarizeReleaseNote: async (content, { maxLen }) => {
const openai = new OpenAI({ apiKey: openaiApiKey });
Expand Down
18 changes: 13 additions & 5 deletions src/infrastructures/implementSlackPresenter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { type MessageHelper, type MessengerPresenter } from '../presenters/MessengerPresenter';
import type {
MessageHelper,
MessengerPresenter,
} from '../presenters/MessengerPresenter';

export const implementSlackPresenter = ({
slackAuthToken,
Expand All @@ -8,17 +11,19 @@ export const implementSlackPresenter = ({
channelId: string;
}): MessengerPresenter => {
return {
sendMessage: async (getter) => {
sendMessage: (getter) => {
const { text, options } = getter(helpers);
return postMessage({ channelId, slackAuthToken, text, options });
},
};
};

const escapeSymbols = (text: string) => text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const escapeSymbols = (text: string) =>
text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

const helpers: MessageHelper = {
formatLink: (text: string, options: { url: string }) => `<${options.url}|${escapeSymbols(text)}>`,
formatLink: (text: string, options: { url: string }) =>
`<${options.url}|${escapeSymbols(text)}>`,
formatChannel: (channelId: string) => `<#${channelId}>`,
formatEmoji: (emoji: string) => `:${emoji}:`,
formatBold: (text: string) => `*${text}*`,
Expand All @@ -39,7 +44,10 @@ const postMessage = async ({
}) => {
const response = await fetch('https://slack.com/api/chat.postMessage', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${slackAuthToken}` },
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${slackAuthToken}`,
},
body: JSON.stringify({ channel: channelId, text, thread_ts: options?.ts }),
});
const data = (await response.json()) as unknown;
Expand Down
7 changes: 5 additions & 2 deletions src/presenters/MessengerPresenter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Member } from '../entities/Member';
import type { Member } from '../entities/Member';

export type MessageHelper = {
formatLink: (text: string, options: { url: string }) => string;
Expand All @@ -9,7 +9,10 @@ export type MessageHelper = {
formatCodeBlock: (text: string) => string;
};

type MessageGetter = (helper: MessageHelper) => { text: string; options?: { ts?: string } };
type MessageGetter = (helper: MessageHelper) => {
text: string;
options?: { ts?: string };
};

export type MessengerPresenter = {
sendMessage: (getter: MessageGetter) => Promise<{ ts: string }>;
Expand Down
37 changes: 27 additions & 10 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SlackEvent } from './entities/Slack';
import type { SlackEvent } from './entities/Slack';
import { implementGitHubDeployWebhookController } from './infrastructures/implementGitHubDeployWebhookController';
import { implementMemberWaffleDotComRepository } from './infrastructures/implementMemberWaffleDotComRepository';
import { implementOpenAiSummarizeRepository } from './infrastructures/implementOpenAiSummarizeRepository';
Expand All @@ -14,8 +14,10 @@ const openaiApiKey = process.env.OPENAI_API_KEY;

if (slackAuthToken === undefined) throw new Error('Missing Slack Auth Token');
if (slackBotToken === undefined) throw new Error('Missing Slack Bot Token');
if (slackWatcherChannelId === undefined) throw new Error('Missing Slack Watcher Channel ID');
if (deployWatcherChannelId === undefined) throw new Error('Missing Deploy Watcher Channel ID');
if (slackWatcherChannelId === undefined)
throw new Error('Missing Slack Watcher Channel ID');
if (deployWatcherChannelId === undefined)
throw new Error('Missing Deploy Watcher Channel ID');
if (openaiApiKey === undefined) throw new Error('Missing OpenAI API Key');

const PORT = 3000;
Expand All @@ -32,7 +34,9 @@ const deployWebhookController = implementGitHubDeployWebhookController({
slackAuthToken,
channelId: deployWatcherChannelId,
}),
summarizeLLMRepository: implementOpenAiSummarizeRepository({ openaiApiKey }),
summarizeLLMRepository: implementOpenAiSummarizeRepository({
openaiApiKey,
}),
memberRepository: implementMemberWaffleDotComRepository(),
}),
});
Expand All @@ -43,18 +47,31 @@ Bun.serve({
const url = new URL(req.url);
try {
if (req.method === 'POST' && url.pathname === '/slack/action-endpoint') {
const body = (await req.json()) as { token: unknown; type: string; challenge: string; event: SlackEvent };
if (body.token !== slackBotToken) return new Response(null, { status: 403 });
const body = (await req.json()) as {
token: unknown;
type: string;
challenge: string;
event: SlackEvent;
};
if (body.token !== slackBotToken)
return new Response(null, { status: 403 });
if (body.type === 'url_verification')
return new Response(slackService.handleVerification(body), { status: 200 });
return new Response(slackService.handleVerification(body), {
status: 200,
});
await slackService.handleEvent(body.event);
return new Response(null, { status: 200 });
} else if (req.method === 'POST' && url.pathname === '/github/webhook-endpoint') {
}

if (
req.method === 'POST' &&
url.pathname === '/github/webhook-endpoint'
) {
await deployWebhookController.handle(await req.json());
return new Response(null, { status: 200 });
} else {
throw new Error();
}

throw new Error('Not Found');
} catch (_) {
return new Response(null, { status: 500 });
}
Expand Down
Loading
Loading