diff --git a/.vscode/launch.json b/.vscode/launch.json index 9974379e..ca2f6750 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,6 +27,7 @@ "run-script", "test", "--", + "--colors", "${input:testFilterArgument}" ], "internalConsoleOptions": "openOnSessionStart", @@ -48,8 +49,8 @@ { "id": "testFilterArgument", "type": "promptString", - "description": "実行するユニットテストの正規表現フィルタ", - "default": "**/*.{js,ts}" + "description": "実行するユニットテストの正規表現フィルタ (全部実行する場合は空文字列を入力)", + "default": "" } ] } \ No newline at end of file diff --git a/helloworld/HelloWorld.test.ts b/helloworld/HelloWorld.test.ts index 153c17b6..f37eec8f 100644 --- a/helloworld/HelloWorld.test.ts +++ b/helloworld/HelloWorld.test.ts @@ -33,7 +33,7 @@ describe('helloworld', () => { it('responds to "Hello"', async () => { const response = await slack.getResponseTo('Hello'); expect(response).toEqual({ - username: 'helloworld [test-hostname]', + username: 'helloworld [TEST_AUTHORITY]', channel: slack.fakeChannel, text: 'World!', }); @@ -59,7 +59,7 @@ describe('helloworld', () => { const mockedPostMessage = slack.webClient.chat.postMessage as jest.MockedFunction; expect(mockedPostMessage).toBeCalledWith({ - username: 'helloworld [test-hostname]', + username: 'helloworld [TEST_AUTHORITY]', channel: slack.fakeChannel, text: 'Hello, World!', blocks: [ @@ -113,7 +113,7 @@ describe('helloworld', () => { elements: [ { type: 'plain_text', - text: '⚠この値は再起動後も保存されます。前回このメッセージを投稿してから60分以上経っている場合はメッセージが再投稿されますが、以前のメッセージの数字は更新されなくなります。ボタンを押すとエラーが出る場合は、「Slackbotを作ろう」ページの「WebSocketトンネルをセットアップする」などを参考に Event API のセットアップが正常にできているかもう一度確認してください。', + text: '⚠この値は再起動後も保存されます。前回このメッセージを投稿してから60分以上経っている場合は、以前のメッセージが削除され再投稿されます。ボタンを押すとエラーが出る場合は、「Slackbotを作ろう」ページの「WebSocketトンネルをセットアップする」などを参考に Event API のセットアップが正常にできているかもう一度確認してください。', emoji: true, }, ], diff --git a/helloworld/HelloWorld.ts b/helloworld/HelloWorld.ts index d2e7fecd..a7404949 100644 --- a/helloworld/HelloWorld.ts +++ b/helloworld/HelloWorld.ts @@ -1,13 +1,12 @@ import {randomUUID} from 'crypto'; import type EventEmitter from 'events'; -import os from 'os'; import type {BlockAction, ViewSubmitAction} from '@slack/bolt'; import type {SlackMessageAdapter} from '@slack/interactive-messages'; import type {MessageEvent, WebClient} from '@slack/web-api'; import {Mutex} from 'async-mutex'; import logger from '../lib/logger'; import type {SlackInterface} from '../lib/slack'; -import {extractMessage} from '../lib/slackUtils'; +import {extractMessage, getAuthorityLabel} from '../lib/slackUtils'; import State from '../lib/state'; import counterEditDialog from './views/counterEditDialog'; import helloWorldMessage from './views/helloWorldMessage'; @@ -33,6 +32,8 @@ export class HelloWorld { #SANDBOX_ID = process.env.CHANNEL_SANDBOX ?? ''; + #AUTHORITY = getAuthorityLabel(); + // インスタンスを生成するためのファクトリメソッド static async create(slack: SlackInterface) { log.info('Creating helloworld bot instance'); @@ -105,7 +106,7 @@ export class HelloWorld { } private get username() { - return `helloworld [${os.hostname()}]`; + return `helloworld [${this.#AUTHORITY}]`; } // 「Hello, World!」メッセージを#sandboxに送信する diff --git a/index.ts b/index.ts index 7a582779..054fff19 100644 --- a/index.ts +++ b/index.ts @@ -7,7 +7,6 @@ import dotenv from 'dotenv'; dotenv.config(); import Fastify from 'fastify'; -import os from 'os'; import qs from 'querystring'; import { eventClient, messageClient, tsgEventClient, webClient } from './lib/slack'; @@ -23,6 +22,7 @@ import { throttle, uniq } from 'lodash'; import { RequestHandler } from 'express-serve-static-core'; import { inspect } from 'util'; import concat from 'concat-stream'; +import { getAuthorityLabel } from './lib/slackUtils'; const log = logger.child({ bot: 'index' }); @@ -187,9 +187,10 @@ eventClient.on('error', (error) => { fastify.use('/slack-message', messageClient.requestListener()); const loadedPlugins = new Set(); + const authority = getAuthorityLabel(); const initializationMessage = await webClient.chat.postMessage({ - username: `tsgbot [${os.hostname()}]`, + username: `tsgbot [${authority}]`, channel: process.env.CHANNEL_SANDBOX, text: `起動中⋯⋯ (${loadedPlugins.size}/${plugins.length})`, attachments: plugins.map((name) => ({ @@ -246,7 +247,7 @@ eventClient.on('error', (error) => { log.info('Launched'); webClient.chat.postMessage({ - username: `tsgbot [${os.hostname()}]`, + username: `tsgbot [${authority}]`, channel: process.env.CHANNEL_SANDBOX, text: argv.startup, }); diff --git a/lib/__mocks__/slackUtils.ts b/lib/__mocks__/slackUtils.ts index 9fb691a8..d0318d02 100644 --- a/lib/__mocks__/slackUtils.ts +++ b/lib/__mocks__/slackUtils.ts @@ -1,6 +1,6 @@ /* eslint-env node, jest */ -import {MrkdwnElement, PlainTextElement} from '@slack/web-api'; -import type {MessageEvent} from '@slack/bolt'; +import { MrkdwnElement, PlainTextElement } from '@slack/web-api'; +import type { MessageEvent } from '@slack/bolt'; export const getMemberName = jest.fn(async () => 'Dummy User'); export const getMemberIcon = jest.fn(async () => 'https://example.com/dummy.png'); @@ -18,4 +18,8 @@ export const mrkdwn = (text: string): MrkdwnElement => ({ export const extractMessage = (message: MessageEvent) => { return message; +}; + +export const getAuthorityLabel = () => { + return 'TEST_AUTHORITY'; }; \ No newline at end of file diff --git a/lib/slackUtils.ts b/lib/slackUtils.ts index 3e683ca2..286f5e9f 100644 --- a/lib/slackUtils.ts +++ b/lib/slackUtils.ts @@ -1,10 +1,11 @@ -import type {MrkdwnElement, PlainTextElement} from '@slack/web-api'; -import type {Member} from '@slack/web-api/dist/types/response/UsersListResponse'; -import {WebClient} from '@slack/web-api'; -import {eventClient, getTokens} from './slack'; -import {Deferred} from './utils'; +import type { MrkdwnElement, PlainTextElement } from '@slack/web-api'; +import type { Member } from '@slack/web-api/dist/types/response/UsersListResponse'; +import { WebClient } from '@slack/web-api'; +import { eventClient, getTokens } from './slack'; +import { Deferred } from './utils'; import SlackCache from './slackCache'; -import type {GenericMessageEvent, MessageEvent} from '@slack/bolt'; +import type { GenericMessageEvent, MessageEvent } from '@slack/bolt'; +import os from 'os'; const slackCaches = new Map(); const initializedSlackCachesDeferred = new Deferred(); @@ -34,11 +35,11 @@ export const getAllTSGMembers = async (): Promise> => { return await slackCaches.get(process.env.TEAM_ID!)!.getUsers(); }; -export const getMemberName = async (user: string): Promise => { +export const getMemberName = async (user: string): Promise => { await initializedSlackCachesDeferred.promise; // TODO: receive team_id and use it to choose slackCache - let member: Member|null = null; + let member: Member | null = null; for (const caches of slackCaches.values()) { const found = await caches.getUser(user); if (found) { @@ -51,11 +52,11 @@ export const getMemberName = async (user: string): Promise => }; type IconResolution = 24 | 32 | 48 | 72 | 192 | 512; -export const getMemberIcon = async (user: string, res: IconResolution = 24): Promise => { +export const getMemberIcon = async (user: string, res: IconResolution = 24): Promise => { await initializedSlackCachesDeferred.promise; // TODO: receive team_id and use it to choose slackCache - let member: Member|null = null; + let member: Member | null = null; for (const caches of slackCaches.values()) { const found = await caches.getUser(user); if (found) { @@ -82,7 +83,7 @@ export const getMemberIcon = async (user: string, res: IconResolution = 24): Pro } }; -export const getEmoji = async (name: string, team: string): Promise => { +export const getEmoji = async (name: string, team: string): Promise => { await initializedSlackCachesDeferred.promise; return slackCaches.get(team)?.getEmoji(name); }; @@ -113,4 +114,19 @@ export const extractMessage = (message: MessageEvent) => { return message.root; } return null; +}; + +export const getAuthorityLabel = () => { + if (process.env.NODE_ENV === 'production') { + return 'production'; + } + + if (process.env.GITHUB_USER && process.env.CODESPACE_NAME) { + const abbreviatedCodespaceName = process.env.CODESPACE_NAME.split('-')[0] + '-…'; + return `Codespaces (@${process.env.GITHUB_USER}): ${abbreviatedCodespaceName}`; + } + + const username = process.env.GITHUB_USER || process.env.USER || process.env.USERNAME || os.userInfo()?.username || 'unknown'; + const hostname = process.env.CODESPACE_NAME || os.hostname() || 'unknown'; + return `${username}@${hostname}`; }; \ No newline at end of file diff --git a/package.json b/package.json index 87a6544a..c6e8a3da 100644 --- a/package.json +++ b/package.json @@ -169,4 +169,4 @@ "ts-jest": "^29.0.0", "ts-node-dev": "^2.0.0" } -} +} \ No newline at end of file