diff --git a/packages/cli/src/constructs/__tests__/telegram-alert-channel-codegen.spec.ts b/packages/cli/src/constructs/__tests__/telegram-alert-channel-codegen.spec.ts new file mode 100644 index 00000000..07917fd9 --- /dev/null +++ b/packages/cli/src/constructs/__tests__/telegram-alert-channel-codegen.spec.ts @@ -0,0 +1,61 @@ +import { mkdtemp, readFile, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import path from 'node:path' + +import { afterEach, beforeEach, describe, expect, it } from 'vitest' + +import { TelegramAlertChannelCodegen, type TelegramAlertChannelResource } from '../telegram-alert-channel-codegen.js' +import { Context } from '../internal/codegen/index.js' +import { Program } from '../../sourcegen/index.js' + +describe('TelegramAlertChannelCodegen', () => { + let rootDirectory: string + + beforeEach(async () => { + rootDirectory = await mkdtemp(path.join(tmpdir(), 'telegram-alert-channel-codegen-')) + }) + + afterEach(async () => { + await rm(rootDirectory, { recursive: true, force: true }) + }) + + it('preserves the message thread ID when exporting a Telegram alert channel', async () => { + const program = new Program({ + rootDirectory, + constructFileSuffix: '.check', + specFileSuffix: '.spec', + language: 'typescript', + }) + const codegen = new TelegramAlertChannelCodegen(program) + const context = new Context() + const resource: TelegramAlertChannelResource = { + id: 123, + type: 'WEBHOOK', + config: { + name: 'Telegram topic', + webhookType: 'WEBHOOK_TELEGRAM', + url: 'https://api.telegram.org/bot123456:ABC/sendMessage', + method: 'POST', + headers: [], + template: 'chat_id=-701234567&message_thread_id=42&parse_mode=HTML&text=test', + }, + sendRecovery: true, + sendFailure: true, + sendDegraded: false, + sslExpiry: false, + sslExpiryThreshold: 30, + } + + codegen.prepare('telegram-topic', resource, context) + codegen.gencode('telegram-topic', resource, context) + await program.realize() + + const [filePath] = program.paths + if (filePath === undefined) { + throw new Error('Codegen did not register a generated file') + } + const source = await readFile(filePath, 'utf8') + + expect(source).toContain(`messageThreadId: '42'`) + }) +}) diff --git a/packages/cli/src/constructs/__tests__/telegram-alert-channel.spec.ts b/packages/cli/src/constructs/__tests__/telegram-alert-channel.spec.ts new file mode 100644 index 00000000..5557a6b7 --- /dev/null +++ b/packages/cli/src/constructs/__tests__/telegram-alert-channel.spec.ts @@ -0,0 +1,47 @@ +import { beforeEach, describe, expect, it } from 'vitest' + +import { Project } from '../project.js' +import { Session } from '../session.js' +import { TelegramAlertChannel } from '../telegram-alert-channel.js' + +describe('TelegramAlertChannel', () => { + beforeEach(() => { + Session.project = new Project('project-id', { + name: 'Test Project', + repoUrl: 'https://github.com/checkly/checkly-cli', + }) + }) + + it('includes the message thread ID in the Telegram request template', () => { + const channel = new TelegramAlertChannel('telegram-topic', { + name: 'Telegram topic', + apiKey: '123456:ABC', + chatId: '-701234567', + messageThreadId: '42', + payload: 'test', + }) + + expect(channel.synthesize()).toMatchObject({ + type: 'WEBHOOK', + config: { + webhookType: 'WEBHOOK_TELEGRAM', + template: 'chat_id=-701234567&message_thread_id=42&parse_mode=HTML&text=test', + }, + }) + }) + + it('keeps the existing template shape when no message thread ID is configured', () => { + const channel = new TelegramAlertChannel('telegram-chat', { + name: 'Telegram chat', + apiKey: '123456:ABC', + chatId: '-701234567', + payload: 'test', + }) + + expect(channel.synthesize()).toMatchObject({ + config: { + template: 'chat_id=-701234567&parse_mode=HTML&text=test', + }, + }) + }) +}) diff --git a/packages/cli/src/constructs/telegram-alert-channel-codegen.ts b/packages/cli/src/constructs/telegram-alert-channel-codegen.ts index d499625d..f2580d0d 100644 --- a/packages/cli/src/constructs/telegram-alert-channel-codegen.ts +++ b/packages/cli/src/constructs/telegram-alert-channel-codegen.ts @@ -21,6 +21,7 @@ function apiKeyFromUrl (url: string): string | undefined { interface TemplateValues { chatId?: string + messageThreadId?: string text?: string } @@ -37,6 +38,7 @@ function parseTemplate (template: string): TemplateValues { return { chatId: singleValue('chat_id'), + messageThreadId: singleValue('message_thread_id'), text: singleValue('text'), } } @@ -110,13 +112,17 @@ export class TelegramAlertChannelCodegen extends Codegen{{this}} {{#unless @last}},{{/unless}} {{/eac this.webhookType = 'WEBHOOK_TELEGRAM' this.method = 'POST' const payload = props.payload ?? TelegramAlertChannel.DEFAULT_PAYLOAD + const messageThreadPart = props.messageThreadId + ? `&message_thread_id=${props.messageThreadId}` + : '' // For historical reasons the payload is not escaped even though it // should be. - this.template = `chat_id=${props.chatId}&parse_mode=HTML&text=${payload}` + this.template = `chat_id=${props.chatId}${messageThreadPart}&parse_mode=HTML&text=${payload}` this.url = `https://api.telegram.org/bot${props.apiKey}/sendMessage` }