.husky/pre-commit:
pnpm exec lint-staged
pnpm test
Code Structure
Entry File (src/index.ts)
import { PrismaClient } from "@prisma/client";
import { PrismaD1 } from "@prisma/adapter-d1";
import { Bot, webhookCallback } from "grammy";
export interface Env {
BOT_TOKEN: string;
BOT_INFO: string;
DB: D1Database;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const adapter = new PrismaD1(env.DB);
const prisma = new PrismaClient({ adapter });
const bot = new Bot(env.BOT_TOKEN, {
botInfo: JSON.parse(env.BOT_INFO),
});
bot.command("start", async (ctx) => {
const user = ctx.from;
if (user) {
await prisma.user.upsert({
where: { telegramId: BigInt(user.id) },
update: { username: user.username, firstName: user.first_name },
create: {
telegramId: BigInt(user.id),
username: user.username,
firstName: user.first_name,
},
});
}
await ctx.reply("Welcome to the Bot!");
});
return webhookCallback(bot, "cloudflare-mod")(request);
},
};
GitHub Actions CI/CD
Workflow Overview
| dev
| push
| development (my-telegram-bot-dev)
| main
| push
| production (my-telegram-bot)
| PR |
|---|
| Tests only, no deployment |
.github/workflows/ci.yml
name: CI/CD
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm exec prisma generate
- run: pnpm run lint
- run: pnpm run test
deploy-dev:
needs: test
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
environment: development
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- run: pnpm install --frozen-lockfile
- run: pnpm exec prisma generate
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
environment: dev
deploy-production:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- run: pnpm install --frozen-lockfile
- run: pnpm exec prisma generate
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
environment: production
GitHub Configuration
Secrets (Settings → Secrets and variables → Actions):
CLOUDFLARE_API_TOKEN: Cloudflare API Token
Environments (Settings → Environments):
-
development: Optional protection rules -
production: Recommend configuring Required reviewers
Deployment
Manual Deployment
# Deploy to development
pnpm exec wrangler deploy --env dev
# Deploy to production
pnpm exec wrangler deploy --env production
Set Secrets
# Development
pnpm exec wrangler secret put BOT_TOKEN --env dev
# Production
pnpm exec wrangler secret put BOT_TOKEN --env production
Set Webhook
# Development
curl "https://api.telegram.org/bot<DEV_TOKEN>/setWebhook?url=https://my-telegram-bot-dev.<subdomain>.workers.dev/"
# Production
curl "https://api.telegram.org/bot<PROD_TOKEN>/setWebhook?url=https://my-telegram-bot.<subdomain>.workers.dev/"