Skip to content

Commit

Permalink
Merge branch 'master' into dev/settyan117/city-symbol-specify-pref
Browse files Browse the repository at this point in the history
  • Loading branch information
settyan117 committed Oct 20, 2024
2 parents 422ca9a + 96f0c69 commit ff1b21e
Show file tree
Hide file tree
Showing 62 changed files with 61,167 additions and 58,129 deletions.
1 change: 1 addition & 0 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HTTP_PROXY_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
28 changes: 28 additions & 0 deletions .devcontainer/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
slackbot:
# build: slackbot
image: ghcr.io/tsg-ut/slackbot-codespaces-image-slackbot:master
volumes:
- ..:/code
- /code/node_modules
- /code/functions/node_modules
stdin_open: true
tty: true
command: sleep infinity
environment:
- TEAM_ID=${TEAM_ID}
- SIGNING_SECRET=${SIGNING_SECRET}
- SLACK_TOKEN=${SLACK_TOKEN}
- HAKATASHI_TOKEN=${HAKATASHI_TOKEN}
- CHANNEL_SANDBOX=${CHANNEL_SANDBOX}
- SLACK_VERIFICATION_TOKEN=${SLACK_VERIFICATION_TOKEN}

tunnel:
build:
context: tunnel
dockerfile: Dockerfile
args:
- HTTP_PROXY_TOKEN=${HTTP_PROXY_TOKEN}
stdin_open: true
tty: true
command: node index.mjs --remote wss://slackbot-api.tsg.ne.jp/wsfwd --host slackbot
44 changes: 44 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
{
"name": "Node.js",
"dockerComposeFile": "compose.yaml",
"service": "slackbot",
"workspaceFolder": "/code",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": "true",
"username": "slackbot",
"upgradePackages": "true"
}
},
"runServices": [
"slackbot",
"tunnel"
],
"postAttachCommand": "docker logs slackbot_devcontainer-tunnel-1 && docker attach slackbot_devcontainer-tunnel-1",
"customizations": {
"vscode": {
"settings": {
"files.autoSave": "off",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "always",
"source.fixAll.eslint": "always"
},
"eslint.format.enable": true
},
"extensions": [
"ms-vscode.vscode-typescript-next",
"dbaeumer.vscode-eslint",
"GitHub.copilot",
"GitHub.copilot-chat",
"GitHub.vscode-pull-request-github",
"toba.vsfire"
]
}
}
}
24 changes: 24 additions & 0 deletions .devcontainer/slackbot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM node:20-bookworm

RUN apt-get update -y && \
# Install build dependencies for node-canvas
# https://github.com/Automattic/node-canvas/wiki/Installation%3A-Ubuntu-and-other-Debian-based-systems
apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev -y && \
# Install git and bash
apt-get install git bash -y && \
# Install ngrok
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc | tee /etc/apt/trusted.gpg.d/ngrok.asc > /dev/null && \
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | tee /etc/apt/sources.list.d/ngrok.list && \
apt-get update && \
apt-get install ngrok -y && \
# Install slackbot npm dependencies
mkdir -p ~/.cache/slackbot/node_modules && \
mkdir -p ~/.cache/slackbot-functions/node_modules && \
git clone https://github.com/tsg-ut/slackbot.git --branch master --single-branch --recursive --depth 1 /code && \
cd /code && \
npm install && \
# Cleanup
apt-get clean && \
rm -rf /var/lib/apt/lists/*

WORKDIR /code
10 changes: 10 additions & 0 deletions .devcontainer/tunnel/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM node:20-bookworm
ARG HTTP_PROXY_TOKEN

RUN apt-get update -y && \
apt-get install git bash -y && \
git clone https://${HTTP_PROXY_TOKEN}@github.com/tsg-ut/http-local-fwd.git && \
cd http-local-fwd/local && \
npm install

WORKDIR /http-local-fwd/local
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ TWITTER_ACCESS_TOKEN_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# checkin
SWARM_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

# channel-notifier, tahoiya, wordle-battle
# channel-notifier, tahoiya, wordle-battle, topic
USER_TSGBOT=UXXXXXXXX

# deploy
Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/codespaces-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Create and publish a Codespaces Docker image

on:
push:
branches:
- master

env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write
attestations: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image (slackbot)
id: push_slackbot
uses: docker/build-push-action@v6
with:
context: .devcontainer/slackbot
push: true
tags: ghcr.io/tsg-ut/slackbot-codespaces-image-slackbot:master

- name: Generate artifact attestation (slackbot)
uses: actions/attest-build-provenance@v1
with:
subject-name: ghcr.io/tsg-ut/slackbot-codespaces-image-slackbot
subject-digest: ${{ steps.push_slackbot.outputs.digest }}
push-to-registry: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ tokens.sqlite3
.DS_Store

.vscode
!.vscode/launch.json
56 changes: 56 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Slackbot起動",
"type": "node",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run-script",
"dev",
"--",
"--only",
"${input:onlyArgument}"
],
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"console": "internalConsole",
"outputCapture": "std"
},
{
"name": "ユニットテストの実行",
"type": "node",
"runtimeExecutable": "npm",
"args": [
"run-script",
"test",
"--",
"--colors",
"${input:testFilterArgument}"
],
"internalConsoleOptions": "openOnSessionStart",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"console": "internalConsole",
"outputCapture": "std"
}
],
"inputs": [
{
"id": "onlyArgument",
"type": "promptString",
"description": "起動するBOTの種類",
"default": "helloworld"
},
{
"id": "testFilterArgument",
"type": "promptString",
"description": "実行するユニットテストの正規表現フィルタ (全部実行する場合は空文字列を入力)",
"default": ""
}
]
}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# slackbot

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/tsg-ut/slackbot?quickstart=1)

[![Test][action-image]][action-url]
[![Coverage Status][codecov-image]][codecov-url]

Expand All @@ -13,13 +15,11 @@

TSGのSlackで動くSlackbotたち

自分がOWNERのコードの変更は直接masterにpushして構いません。 ([CODEOWNERS](CODEOWNERS)参照)

## 環境構築

### Prerequisites

* Node.js Latest
* Node.js v20

### セットアップ

Expand Down
2 changes: 1 addition & 1 deletion achievement-quiz/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ beforeEach(() => {
describe('response to /^実績当てクイズ$/', () => {
it('starts game by "実績当てクイズ"', async () => {
const response = await slack.getResponseTo('実績当てクイズ');
expect(response.username).toBe('実績当てクイズ');
expect('username' in response && response.username).toBe('実績当てクイズ');
expect(response.text).toContain('この実績なーんだ');
});
});
7 changes: 4 additions & 3 deletions achievements/index_production.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ beforeEach(() => {

describe('achievements', () => {
it('unlock chat achievement when chat is posted', async () => {
const {text, username} = await slack.getResponseTo('hoge');
expect(username).toBe('achievements');
expect(text).toContain('はじめまして!');
const response = await slack.getResponseTo('hoge');
// eslint-disable-next-line no-restricted-syntax
expect('username' in response && response.username).toBe('achievements');
expect(response.text).toContain('はじめまして!');
});
});
27 changes: 17 additions & 10 deletions atequiz/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { WebAPICallOptions, WebClient } from '@slack/web-api';
import { ChatPostMessageArguments, WebClient } from '@slack/web-api';
import type { EventEmitter } from 'events';
import { SlackInterface } from '../lib/slack';
import { ChatPostMessageArguments } from '@slack/web-api/dist/methods';
import assert from 'assert';
import { Mutex } from 'async-mutex';
import { Deferred } from '../lib/utils';
Expand Down Expand Up @@ -70,7 +69,7 @@ export class AteQuiz {
state: AteQuizState = 'waiting';
replaceKeys: { correctAnswerer: string } = { correctAnswerer: '[[!user]]' };
mutex: Mutex;
postOption: WebAPICallOptions;
postOption: Partial<ChatPostMessageArguments>;
threadTsDeferred: Deferred<string> = new Deferred();

judge(answer: string, _user: string): boolean {
Expand Down Expand Up @@ -119,7 +118,7 @@ export class AteQuiz {
constructor(
{ eventClient, webClient: slack }: SlackInterface,
problem: AteQuizProblem,
option?: WebAPICallOptions
option?: Partial<ChatPostMessageArguments>,
) {
this.eventClient = eventClient;
this.slack = slack;
Expand All @@ -138,8 +137,7 @@ export class AteQuiz {
async repostProblemMessage() {
const threadTs = await this.threadTsDeferred.promise;
return this.slack.chat.postMessage({
...this.problem.problemMessage,
...this.postOption,
...Object.assign({}, this.problem.problemMessage, this.postOption),
thread_ts: threadTs,
reply_broadcast: true,
});
Expand Down Expand Up @@ -187,13 +185,17 @@ export class AteQuiz {
} else {
this.state = 'unsolved';
await postMessage(
Object.assign({}, this.problem.unsolvedMessage, { thread_ts })
Object.assign(
{},
this.problem.unsolvedMessage,
{ thread_ts, reply_broadcast: true },
)
);

const answerMessage = await this.answerMessageGen();
if (this.problem.answerMessage) {
if (answerMessage) {
await postMessage(
Object.assign({}, this.problem.answerMessage, { thread_ts })
Object.assign({}, answerMessage, { thread_ts })
);
}
clearInterval(tickTimer);
Expand All @@ -204,6 +206,7 @@ export class AteQuiz {
};

this.eventClient.on('message', async (message) => {
const thread_ts = await this.threadTsDeferred.promise;
if (message.thread_ts === thread_ts) {
if (message.subtype === 'bot_message') return;
if (_option.mode === 'solo' && message.user !== _option.player) return;
Expand All @@ -216,7 +219,11 @@ export class AteQuiz {
clearInterval(tickTimer);

await postMessage(
Object.assign({}, await this.solvedMessageGen(message), { thread_ts })
Object.assign(
{},
await this.solvedMessageGen(message),
{ thread_ts, reply_broadcast: true },
)
);

const answerMessage = await this.answerMessageGen(message);
Expand Down
16 changes: 11 additions & 5 deletions auto-archiver/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ describe('auto-archiver', () => {
'引き続きこのチャンネルを使用しますか?',
].join('\n'));
expect(mockedPostMessage.mock.calls[0][0].channel).toBe(FAKE_CHANNEL);
expect(mockedPostMessage.mock.calls[0][0].blocks).toHaveLength(3);
// eslint-disable-next-line no-restricted-syntax
const blocks = 'blocks' in mockedPostMessage.mock.calls[0][0] ? mockedPostMessage.mock.calls[0][0].blocks : [];
expect(blocks).toHaveLength(3);

const MockedState = State as MockedStateInterface<StateObj>;
const state = MockedState.mocks.get('auto-archiver_state');
Expand Down Expand Up @@ -218,8 +220,10 @@ describe('auto-archiver', () => {
].join('\n'));
expect(mockedUpdateMessage.mock.calls[0][0].channel).toBe(FAKE_CHANNEL);
expect(mockedUpdateMessage.mock.calls[0][0].ts).toBe(FAKE_TIMESTAMP);
expect(mockedUpdateMessage.mock.calls[0][0].blocks).toHaveLength(3);
expect((mockedUpdateMessage.mock.calls[0][0].blocks[1] as SectionBlock).text.text).toBe('<@U12345678>の回答: *使用しない*');
// eslint-disable-next-line no-restricted-syntax
const blocks = 'blocks' in mockedUpdateMessage.mock.calls[0][0] ? mockedUpdateMessage.mock.calls[0][0].blocks : [];
expect(blocks).toHaveLength(3);
expect((blocks[1] as SectionBlock).text.text).toBe('<@U12345678>の回答: *使用しない*');
expect(slack.webClient.conversations.archive).toBeCalledWith({
channel: FAKE_CHANNEL,
});
Expand Down Expand Up @@ -284,8 +288,10 @@ describe('auto-archiver', () => {
].join('\n'));
expect(mockedUpdateMessage.mock.calls[0][0].channel).toBe(FAKE_CHANNEL);
expect(mockedUpdateMessage.mock.calls[0][0].ts).toBe(FAKE_TIMESTAMP);
expect(mockedUpdateMessage.mock.calls[0][0].blocks).toHaveLength(3);
expect((mockedUpdateMessage.mock.calls[0][0].blocks[1] as SectionBlock).text.text).toBe('<@U12345678>の回答: *使用する*');
// eslint-disable-next-line no-restricted-syntax
const blocks = 'blocks' in mockedUpdateMessage.mock.calls[0][0] ? mockedUpdateMessage.mock.calls[0][0].blocks : [];
expect(blocks).toHaveLength(3);
expect((blocks[1] as SectionBlock).text.text).toBe('<@U12345678>の回答: *使用する*');

const MockedState = State as MockedStateInterface<StateObj>;
const state = MockedState.mocks.get('auto-archiver_state');
Expand Down
Loading

0 comments on commit ff1b21e

Please sign in to comment.