← Cloudflare Workers / workers / tutorials
Vytvořte Slackbota
V tomto tutoriálu sestavíte Slack ↗ bota pomocí Cloudflare Workers. Váš bot bude využívat GitHub webhooky k odesílání zpráv do kanálu Slack při vytvoření nebo aktualizaci issues a uživatelům umožní vyhledávat GitHub issues přímo ze Slacku pomocí příkazu.
Tento návod je určen lidem, kteří mají zkušenosti s tvorbou webových aplikací. Jako programovací jazyk použijete TypeScript a Hono ↗ jako webový framework. Pokud jste aplikaci vytvořili pomocí nástrojů, jako je Node ↗ a Express ↗, bude vám tento projekt připadat velmi povědomý. Pokud s psaním webových aplikací teprve začínáte, nebo jste už dříve chtěli vytvořit něco jako Slack bota, ale odrazovalo vás nasazení nebo konfigurace, Workers vám umožní soustředit se na psaní kódu a doručování projektů.
Pokud si chcete před pokračováním v tomto tutoriálu projít kód nebo se podívat, jak bot funguje ve skutečném kanálu Slack, finální verzi kódové základny najdete na GitHubu ↗. Z GitHubu můžete přidat vlastní API klíče Slacku a nasadit ho do vlastních kanálů Slack pro testování.
Než začnete
Všechny návody předpokládají, že jste již dokončili Úvodní návod, který vás provede nastavením účtu Cloudflare Workers, C3 ↗, a Wrangler.
Nastavit Slack
Tento tutoriál předpokládá, že již máte účet Slack a oprávnění vytvářet a spravovat aplikace Slack.
Nakonfigurujte aplikaci Slack
Chcete-li odesílat zprávy z Cloudflare Workeru do kanálu Slack, budete muset vytvořit aplikaci v UI Slacku. Za tímto účelem přejděte do sekce API Slacku na api.slack.com/apps ↗, a vyberte Create New App.
Slack aplikace nabízí mnoho funkcí. Pro vytvoření Slack bota poháněného Workerem využijete dvě z nich: Incoming Webhooks a Slash Commands.
Incoming Webhook
Incoming Webhooks jsou URL adresy, které můžete použít k odesílání zpráv do kanálů Slacku. Váš incoming webhook se propojí s podporou webhooků v GitHubu a bude odesílat zprávy do kanálu Slacku vždy, když dojde k aktualizaci issues v daném repozitáři. Kód si podrobněji ukážeme při tvorbě aplikace. Nejprve vytvořte webhook Slacku:
- V postranním panelu uživatelského rozhraní Slacku vyberte Incoming Webhooks.
- V URL adresy webhooků pro váš Workspace, vyberte Add New Webhook to Workspace.
- Na následující obrazovce vyberte kanál, do kterého má váš webhook odesílat zprávy (můžete vybrat místnost, například #general nebo #code, nebo nechat, aby vás váš Slack bot při volání webhooku kontaktoval přímo).
- Autorizujte novou URL adresu webhooku.
Po autorizaci adresy URL webhooku budete přesměrováni zpět na Incoming Webhooks stránku a zobrazíte si novou webhook URL. Tu do kódu Workers přidáte později. Dále přidáte druhou součást vašeho Slack bota: Slash Command.
Slash Command
Slash Command ve Slacku je vlastní nakonfigurovaný příkaz, který lze napojit na URL požadavek. Pokud byste například nakonfigurovali /weather <zip>, Slack by odeslal požadavek HTTP POST na nakonfigurovanou URL adresu a předal text <zip> abyste získali počasí pro zadané PSČ. Ve své aplikaci použijete /issue příkaz pro vyhledávání GitHub issues pomocí GitHub API ↗. Typování /issue cloudflare/wrangler#1 odešle text cloudflare/wrangler#1 v HTTP POST požadavku na vaši aplikaci, který aplikace použije k nalezení příslušný GitHub issue ↗.
- V postranním panelu Slacku vyberte Slash Commands.
- Vytvořte svůj první slash command.
V tomto tutoriálu použijete příkaz /issue. URL požadavku by měla být /lookup cestu na URL vaší aplikace: pokud bude vaše aplikace hostovaná například na https://myworkerurl.com, Request URL by mělo být https://myworkerurl.com/lookup.
Nakonfigurujte GitHub Webhooks
Vaše aplikace v Cloudflare Workers bude umět zpracovávat příchozí požadavky ze Slacku. Zároveň by měla umět přijímat události přímo z GitHubu. Pokud je na GitHubu vytvořen nebo upraven issue, můžete pomocí GitHub webhooks tuto událost odeslat do své aplikace ve Workers a zveřejnit odpovídající zprávu ve Slacku.
Chcete-li nakonfigurovat webhook:
- Přejděte do repozitáře na GitHubu do sekce Nastavení > Webhooks > Přidat webhook.
Pokud máte repozitář jako https://github.com/user/repo, můžete přistupovat k Webhooks stránku přímo na adrese https://github.com/user/repo/settings/hooks.
- Nastavte Payload URL na
/webhookcestu na URL vašeho Workeru.
Pokud bude váš Worker hostován například na https://myworkerurl.com, Payload URL by mělo být https://myworkerurl.com/webhook.
- V Typ obsahu rozbalovací nabídce vyberte application/json.
Typ obsahu pro váš payload může mít buď podobu URL kódovaného payloadu (application/x-www-form-urlencoded) nebo JSON (application/json). Pro účely tohoto návodu a kvůli snazšímu parsování datové zprávy odeslané do vaší aplikace zvolte JSON.
- V Které události mají tento webhook spouštět?, vyberte Chci si vybrat jednotlivé události.
Webhooky GitHub vám umožňují určit, které události chcete do svého webhooku odesílat. Ve výchozím nastavení bude webhook odesílat push události z vašeho repozitáře. Pro účely tohoto tutoriálu zvolíte Chci si vybrat jednotlivé události.
- Vyberte Problémy typ události.
Pro váš webhook lze povolit mnoho různých typů událostí. Výběrem Problémy odešle na váš webhook každou událost týkající se issues, včetně jejich otevření, úpravy, smazání a dalších. Pokud budete chtít svou aplikaci Slack bota v budoucnu rozšířit, můžete si po dokončení tutoriálu vybrat další z těchto událostí.
- Vyberte Přidat webhook.
Po vytvoření webhooku se pokusí odeslat testovací payload do vaší aplikace. Protože vaše aplikace zatím ve skutečnosti není nasazená, ponechte konfiguraci beze změny. Později se vrátíte do svého repozitáře a vytvoříte, upravíte a uzavřete několik issues, abyste ověřili, že webhook po nasazení aplikace funguje.
Inicializace
Chcete-li projekt inicializovat, použijte rozhraní příkazové řádky C3 (create-cloudflare-cli) ↗.
npm create cloudflare@latest -- slack-botPodle těchto kroků vytvořte projekt Hono.
- Pro S čím byste chtěli začít?, vyberte
Framework Starter. - Pro Jaký vývojový framework chcete použít?, vyberte
Hono. - Pro, Chcete nasadit svou aplikaci?, vyberte
No.
Přejděte na slack-bot adresář:
cd slack-botOtevřete src/index.ts v editoru a najděte následující kód.
import { Hono } from "hono";
type Bindings = {
[key in keyof CloudflareBindings]: CloudflareBindings[key];
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/", (c) => {
return c.text("Hello Hono!");
});
export default app;Toto je minimální aplikace využívající Hono. Pokud přijde GET požadavek na cestu /, vrátí odpověď s textem Hello Hono!. Zároveň vrací zprávu 404 Not Found se stavovým kódem 404, pokud dojde k přístupu na jinou cestu nebo s jinou metodou.
Chcete-li aplikaci spustit na svém počítači, spusťte následující příkaz.
npm i -- devPřístup k http://localhost:8787 ve vašem prohlížeči po spuštění serveru a uvidíte zprávu.
Hono vám umožňuje snadno a rychle vytvořit aplikaci Workers.
Sestavit
Nyní vytvoříme Slack bota na Cloudflare Workers.
Oddělení souborů
Svou aplikaci můžete vytvořit v několika souborech, místo abyste všechny endpointy a funkce psali do jednoho souboru. S Hono lze směrování podřízených aplikací přidat do nadřazené aplikace pomocí funkce app.route().
Představte si například následující aplikaci Web API.
import { Hono } from "hono";
const app = new Hono();
app.get("/posts", (c) => c.text("Posts!"));
app.post("/posts", (c) => c.text("Created!", 201));
export default app;Trasy můžete přidat pod /api/v1.
import { Hono } from "hono";
import api from "./api";
const app = new Hono();
app.route("/api/v1", api);
export default app;Vrátí Posts! při přístupu k GET /api/v1/posts.
Slack bot bude mít dvě podřízené aplikace, každá nazvaná "route".
-
lookuptrasa bude přijímat požadavky ze Slacku (odeslané, když uživatel použije/issuepříkazu) a vyhledá odpovídající issue pomocí GitHub API. Tato aplikace bude přidána do/lookupv hlavní aplikaci. -
webhooktrasa se zavolá při změně issue na GitHubu prostřednictvím nakonfigurovaného webhooku. Tato aplikace se přidá do/webhookv hlavní aplikaci.
Vytvořte soubory tras ve složce s názvem routes.
mkdir -p src/routes
touch src/routes/lookup.ts
touch src/routes/webhook.tsPoté aktualizujte hlavní aplikaci.
import { Hono } from "hono";
import lookup from "./routes/lookup";
import webhook from "./routes/webhook";
const app = new Hono();
app.route("/lookup", lookup);
app.route("/webhook", webhook);
export default app;Definice typů TypeScript
Než implementujete samotné funkce, musíte definovat typy TypeScript, které v tomto projektu použijete. Vytvořte v aplikaci nový soubor na src/types.ts a napište kód. Bindings je typ, který popisuje proměnné prostředí Cloudflare Workers. Issue je typ pro GitHub issue a User je typ pro uživatele GitHub. Tyto typy budete později potřebovat.
export type Bindings = {
SLACK_WEBHOOK_URL: string;
};
export type Issue = {
html_url: string;
title: string;
body: string;
state: string;
created_at: string;
number: number;
user: User;
};
type User = {
html_url: string;
login: string;
avatar_url: string;
};Vytvoření trasy lookup
Začněte vytvářet route pro vyhledávání v src/routes/lookup.ts.
import { Hono } from "hono";
const app = new Hono();
export default app;Chcete-li pochopit, jak byste měli tuto funkci navrhnout, musíte nejprve pochopit, jak lomítkové příkazy Slacku odesílají data na URL.
Podle dokumentace ke slash příkazům Slacku ↗, Slack odešle požadavek HTTP POST na vámi zadanou URL adresu s application/x-www-form-urlencoded typ obsahu. Pokud by například někdo zadal /issue cloudflare/wrangler#1, můžete očekávat datový payload ve formátu:
token=gIkuvaNzQIHg97ATvDxqgjtO
&team_id=T0001
&team_domain=example
&enterprise_id=E0001
&enterprise_name=Globular%20Construct%20Inc
&channel_id=C2147483705
&channel_name=test
&user_id=U2147483697
&user_name=Steve
&command=/issue
&text=cloudflare/wrangler#1
&response_url=https://hooks.slack.com/commands/1234/5678
&trigger_id=13345224609.738474920.8088930838d88f008e0Toto tělo payloadu musíte zpracovat a získat hodnotu text klíč. S tím text, například cloudflare/wrangler#1, tento řetězec můžete rozložit na známé části dat (owner, repo, a issue_number), a použít ho k odeslání požadavku do GitHub API a načtení dat o issue.
U Slack slash commands můžete na příchozí slash command reagovat tak, že jako odpověď vrátíte strukturovaná data. V tomto případě byste měli použít odpověď z GitHub API k zobrazení naformátované verze GitHub issue, včetně údajů, jako je název issue, kdo ho vytvořil a kdy. Nový Block Kit ↗ framework umožní vrátit podrobnou odpověď se zprávou, a to sestavením textových a obrázkových bloků z dat GitHub API.
Parsování slash commands
Na úvod lookup trasa by měla parsovat zprávy přicházející ze Slacku. Jak již bylo zmíněno, Slack API odesílá HTTP POST ve formátu URL Encoded. Proměnnou můžete získat pomocí text jeho parsováním pomocí c.req.json().
import { Hono } from "hono";
const app = new Hono();
app.post("/", async (c) => {
const { text } = await c.req.parseBody();
if (typeof text !== "string") {
return c.notFound();
}
});
export default app;Máte-li text proměnná, která obsahuje text jako cloudflare/wrangler#1, měli byste tento text rozebrat a získat z něj jednotlivé části pro použití s API GitHubu: owner, repo, a issue_number.
K tomu ve své aplikaci vytvořte nový soubor na src/utils/github.ts. Tento soubor bude obsahovat řadu „utility“ funkcí pro práci s GitHub API. První z nich bude parser řetězců s názvem parseGhIssueString:
const ghIssueRegex =
/(?<owner>[\w.-]*)\/(?<repo>[\w.-]*)\#(?<issue_number>\d*)/;
export const parseGhIssueString = (text: string) => {
const match = text.match(ghIssueRegex);
return match ? (match.groups ?? {}) : {};
};parseGhIssueString přijímá text vstup, porovná jej s ghIssueRegex, a pokud je nalezena shoda, vrátí groups objekt z této shody s využitím owner, repo, a issue_number zachytávacích skupin definovaných v regulárním výrazu. Exportováním této funkce z src/utils/github.ts, můžete jej následně využít zpět v src/handlers/lookup.ts:
import { Hono } from "hono";
import { parseGhIssueString } from "../utils/github";
const app = new Hono();
app.post("/", async (c) => {
const { text } = await c.req.parseBody();
if (typeof text !== "string") {
return c.notFound();
}
const { owner, repo, issue_number } = parseGhIssueString(text);
});
export default app;Odesílání požadavků do GitHub API
S těmito daty můžete provést svůj první API dotaz na GitHub. Opět vytvořte novou funkci v src/utils/github.ts, pro vytvoření fetch požadavek na GitHub API pro data o issue:
const ghIssueRegex =
/(?<owner>[\w.-]*)\/(?<repo>[\w.-]*)\#(?<issue_number>\d*)/;
export const parseGhIssueString = (text: string) => {
const match = text.match(ghIssueRegex);
return match ? (match.groups ?? {}) : {};
};
export const fetchGithubIssue = (
owner: string,
repo: string,
issue_number: string,
) => {
const url = `https://api.github.com/repos/${owner}/${repo}/issues/${issue_number}`;
const headers = { "User-Agent": "simple-worker-slack-bot" };
return fetch(url, { headers });
};Zpět v src/handlers/lookup.ts, použijte fetchGitHubIssue k odeslání požadavku na API GitHubu a zpracování odpovědi:
import { Hono } from "hono";
import { fetchGithubIssue, parseGhIssueString } from "../utils/github";
import { Issue } from "../types";
const app = new Hono();
app.post("/", async (c) => {
const { text } = await c.req.parseBody();
if (typeof text !== "string") {
return c.notFound();
}
const { owner, repo, issue_number } = parseGhIssueString(text);
const response = await fetchGithubIssue(owner, repo, issue_number);
const issue = await response.json<Issue>();
});
export default app;Sestavení zprávy Slack
Jakmile obdržíte odpověď z API GitHubu, posledním krokem je sestavit zprávu Slack s údaji o issue a vrátit ji uživateli. Výsledek bude vypadat přibližně takto:
Na snímku obrazovky výše vidíte čtyři různé části:
- První řádek (tučně) odkazuje na issue a zobrazuje jeho název
- Následující řádky (včetně ukázek kódu) tvoří tělo issue
- Poslední řádek textu zobrazuje stav issue, jejího tvůrce (s odkazem na profil uživatele na GitHubu) a datum vytvoření issue
- Profilový obrázek autora issue na pravé straně
Dříve zmíněný Block Kit ↗ framework pomůže zpracovat data issue (ve struktuře popsané v Dokumentace GitHub REST API ↗) and format it into something like the above screenshot.
Vytvořte další soubor, src/utils/slack.ts, aby obsahoval funkci constructGhIssueSlackMessage, funkci, která vezme data issue a převede je na kolekci bloků. Bloky jsou objekty JavaScript, které Slack použije k formátování zprávy:
import { Issue } from "../types";
export const constructGhIssueSlackMessage = (
issue: Issue,
issue_string: string,
prefix_text?: string,
) => {
const issue_link = `<${issue.html_url}|${issue_string}>`;
const user_link = `<${issue.user.html_url}|${issue.user.login}>`;
const date = new Date(Date.parse(issue.created_at)).toLocaleDateString();
const text_lines = [
prefix_text,
`*${issue.title} - ${issue_link}*`,
issue.body,
`*${issue.state}* - Created by ${user_link} on ${date}`,
];
};Zprávy ve Slacku přijímají variantu Markdownu, která podporuje tučný text pomocí hvězdiček (*bolded text*), a odkazy ve formátu <https://yoururl.com|Display Text>.
Na základě tohoto formátu sestavte issue_link, která přijímá html_url vlastnost z GitHub API issue data (ve formátu https://github.com/cloudflare/wrangler-legacy/issues/1), a issue_string odeslané ze Slack slash command, a spojí je do klikatelného odkazu ve zprávě Slacku.
user_link je podobné a používá issue.user.html_url (ve formátu https://github.com/signalnerve, uživatel GitHub) a uživatelské jméno GitHub (issue.user.login), abyste vytvořili klikací odkaz na uživatele GitHubu.
Nakonec proveďte parsování issue.created_at, řetězec ISO 8601, převeďte jej na instanci JavaScript Date, a převést ji na formátovaný řetězec ve formátu MM/DD/YY.
Jakmile máte tyto proměnné nastavené, text_lines je pole obsahující jednotlivé řádky textu zprávy Slack. První řádek je název issue a odkaz na issue, druhý je tělo issue, a poslední řádek je stav issue (například otevřený nebo zavřený), odkaz uživatele, a datum vytvoření.
Jakmile máte text sestavený, můžete konečně sestavit zprávu pro Slack a vrátit pole bloků pro Slack Block Kit ↗. V tomto případě existuje pouze jeden blok: sekce ↗ blok s textem v Markdown a doprovodným obrázkem uživatele, který issue vytvořil. Tento jediný blok vraťte uvnitř pole, čímž doplníte constructGhIssueSlackMessage funkce:
import { Issue } from "../types";
export const constructGhIssueSlackMessage = (
issue: Issue,
issue_string: string,
prefix_text?: string,
) => {
const issue_link = `<${issue.html_url}|${issue_string}>`;
const user_link = `<${issue.user.html_url}|${issue.user.login}>`;
const date = new Date(Date.parse(issue.created_at)).toLocaleDateString();
const text_lines = [
prefix_text,
`*${issue.title} - ${issue_link}*`,
issue.body,
`*${issue.state}* - Created by ${user_link} on ${date}`,
];
return [
{
type: "section",
text: {
type: "mrkdwn",
text: text_lines.join("\n"),
},
accessory: {
type: "image",
image_url: issue.user.avatar_url,
alt_text: issue.user.login,
},
},
];
};Dokončení route pro vyhledávání
V src/handlers/lookup.ts, použijte constructGhIssueSlackMessage pro sestavení blocks, a vrátit je jako novou odpověď s c.json() když je volán slash příkaz:
import { Hono } from "hono";
import { fetchGithubIssue, parseGhIssueString } from "../utils/github";
import { constructGhIssueSlackMessage } from "../utils/slack";
import { Issue } from "../types";
const app = new Hono();
app.post("/", async (c) => {
const { text } = await c.req.parseBody();
if (typeof text !== "string") {
return c.notFound();
}
const { owner, repo, issue_number } = parseGhIssueString(text);
const response = await fetchGithubIssue(owner, repo, issue_number);
const issue = await response.json<Issue>();
const blocks = constructGhIssueSlackMessage(issue, text);
return c.json({
blocks,
response_type: "in_channel",
});
});
export default app;Dalším parametrem předávaným do odpovědi je response_type. Ve výchozím nastavení jsou odpovědi na slash příkazy dočasné, což znamená, že je vidí pouze uživatel, který slash příkaz zadal. Předáním response_type z in_channel, jak je uvedeno výše, způsobí, že se odpověď zobrazí všem uživatelům v kanálu.
Pokud chcete, aby zprávy zůstaly soukromé, odstraňte response_type řádek. Tím dojde k tomu, že response_type tak, aby výchozí hodnotou bylo ephemeral.
Zpracování chyb
lookup trasa je téměř hotová, ale v ní může dojít k řadě chyb, například při parsování těla ze Slacku, získávání issue z GitHubu nebo sestavování samotné zprávy pro Slack. Aplikace Hono sice dokážou chyby zpracovat i bez dalšího zásahu, ale vrácenou odpověď můžete přizpůsobit následujícím způsobem.
import { Hono } from "hono";
import { fetchGithubIssue, parseGhIssueString } from "../utils/github";
import { constructGhIssueSlackMessage } from "../utils/slack";
import { Issue } from "../types";
const app = new Hono();
app.post("/", async (c) => {
const { text } = await c.req.parseBody();
if (typeof text !== "string") {
return c.notFound();
}
const { owner, repo, issue_number } = parseGhIssueString(text);
const response = await fetchGithubIssue(owner, repo, issue_number);
const issue = await response.json<Issue>();
const blocks = constructGhIssueSlackMessage(issue, text);
return c.json({
blocks,
response_type: "in_channel",
});
});
app.onError((_e, c) => {
return c.text(
"Uh-oh! We couldn't find the issue you provided. " +
"We can only find public issues in the following format: `owner/repo#issue_number`.",
);
});
export default app;Vytvoření trasy webhook
Nyní jste v polovině implementace tras pro vaši aplikaci Workers. Při implementaci další trasy src/routes/webhook.ts, znovu využijete velkou část kódu, který jste už napsali pro trasu lookup.
Na začátku tohoto tutoriálu jste nakonfigurovali GitHub webhook, který sleduje veškeré události související s issues ve vašem repozitáři. Když se například otevře issue, spustí se funkce odpovídající cestě /webhook ve vaší aplikaci Workers by měl převzít data odeslaná z GitHubu a odeslat novou zprávu do nakonfigurovaného kanálu Slacku.
V src/routes/webhook.ts, definujte prázdnou aplikaci Hono. Rozdíl oproti lookup trasa je, že Bindings se předává jako generický parametr pro new Hono(). Je to nutné pro přiřazení odpovídajícího typu TypeScript k SLACK_WEBHOOK_URL která bude použita později.
import { Hono } from "hono";
import { Bindings } from "../types";
const app = new Hono<{ Bindings: Bindings }>();
export default app;Podobně jako u lookup trasu, budete muset parsovat příchozí payload uvnitř request, získejte z něj příslušná data o issue (viz dokumentaci GitHub API na IssueEvent ↗ pro úplné schéma payloadu) a odešlete do Slacku formátovanou zprávu o tom, co se změnilo. Výsledná verze bude vypadat přibližně takto:
Porovnejte tento formát zprávy s formátem, který se vrátí, když uživatel použije /issue slash command. Uvidíte, že mezi nimi je pouze jeden skutečný rozdíl: přidání textu akce na prvním řádku ve formátu An issue was $action:. Tato akce, která se odesílá jako součást IssueEvent z GitHubu, se použijí při sestavování dobře známé kolekce bloků pomocí Slack Block Kit.
Parsování dat události
Chcete-li začít vyplňovat trasu, naparsujte tělo požadavku ve formátu JSON do objektu a vytvořte několik pomocných proměnných:
import { Hono } from "hono";
import { constructGhIssueSlackMessage } from "../utils/slack";
const app = new Hono();
app.post("/", async (c) => {
const { action, issue, repository } = await c.req.json();
const prefix_text = `An issue was ${action}:`;
const issue_string = `${repository.owner.login}/${repository.name}#${issue.number}`;
});
export default app; IssueEvent, payload odeslaný z GitHubu jako součást konfigurace webhooku obsahuje action (co se s issue stalo: bylo například otevřeno, zavřeno, uzamčeno atd.), issue samo o sobě, a repository, mimo jiné.
Použijte c.req.json() pro převod těla požadavku z JSON na obyčejný objekt JS. Pomocí destrukturalizace ES6 nastavte action, issue a repository jako proměnné, které můžete použít ve svém kódu. prefix_text je řetězec označující, co se s daným issue stalo, a issue_string je známý řetězec owner/repo#issue_number kterou jste už viděli: zatímco lookup trasa přímo použila text odeslaný ze Slacku k vyplnění issue_string, sestavíte ho přímo na základě dat předaných v JSON payloadu.
Sestavení a odeslání zprávy Slack
Zprávy, které váš Slack bot odesílá zpět do vašeho Slack kanálu z lookup a webhook trasy jsou si velmi podobné. Díky tomu můžete znovu použít existující constructGhIssueSlackMessage pro další doplňování src/handlers/webhook.ts. Importujte funkci z src/utils/slack.ts, a předat mu data problému:
import { Hono } from "hono";
import { constructGhIssueSlackMessage } from "../utils/slack";
const app = new Hono();
app.post("/", async (c) => {
const { action, issue, repository } = await c.req.json();
const prefix_text = `An issue was ${action}:`;
const issue_string = `${repository.owner.login}/${repository.name}#${issue.number}`;
const blocks = constructGhIssueSlackMessage(issue, issue_string, prefix_text);
});
export default app;Je důležité zmínit, že použití constructGhIssueSlackMessage v tomto handleru přidává funkci jeden další argument, prefix_text. Aktualizujte odpovídající funkci uvnitř src/utils/slack.ts, přidání prefix_text do kolekce text_lines v bloku zprávy, pokud byl předán funkci.
Přidejte pomocnou funkci, compact, která přijímá pole a odfiltruje veškeré null nebo undefined hodnoty z ní. Tato funkce se použije k odstranění prefix_text z text_lines pokud ve skutečnosti nebyl funkci předán, například při volání z src/handlers/lookup.ts. Úplná (a finální) verze src/utils/slack.ts vypadá takto:
import { Issue } from "../types";
const compact = (array: unknown[]) => array.filter((el) => el);
export const constructGhIssueSlackMessage = (
issue: Issue,
issue_string: string,
prefix_text?: string,
) => {
const issue_link = `<${issue.html_url}|${issue_string}>`;
const user_link = `<${issue.user.html_url}|${issue.user.login}>`;
const date = new Date(Date.parse(issue.created_at)).toLocaleDateString();
const text_lines = [
prefix_text,
`*${issue.title} - ${issue_link}*`,
issue.body,
`*${issue.state}* - Created by ${user_link} on ${date}`,
];
return [
{
type: "section",
text: {
type: "mrkdwn",
text: compact(text_lines).join("\n"),
},
accessory: {
type: "image",
image_url: issue.user.avatar_url,
alt_text: issue.user.login,
},
},
];
};Zpět v src/handlers/webhook.ts, blocks které se vracejí z constructGhIssueSlackMessage se stanou tělem v novém fetch požadavek, tedy HTTP POST požadavek na Slack webhook URL. Jakmile se tento požadavek dokončí, vraťte odpověď se stavovým kódem 200, a text těla "OK":
import { Hono } from "hono";
import { constructGhIssueSlackMessage } from "../utils/slack";
import { Bindings } from "../types";
const app = new Hono<{ Bindings: Bindings }>();
app.post("/", async (c) => {
const { action, issue, repository } = await c.req.json();
const prefix_text = `An issue was ${action}:`;
const issue_string = `${repository.owner.login}/${repository.name}#${issue.number}`;
const blocks = constructGhIssueSlackMessage(issue, issue_string, prefix_text);
const fetchResponse = await fetch(c.env.SLACK_WEBHOOK_URL, {
body: JSON.stringify({ blocks }),
method: "POST",
headers: { "Content-Type": "application/json" },
});
return c.text("OK");
});
export default app;Konstanta SLACK_WEBHOOK_URL představuje Slack Webhook URL, kterou jste si vytvořili už na začátku v části Incoming Webhook sekci tohoto tutoriálu.
Chcete-li tuto konstantu použít ve svém kódu, použijte wrangler secret příkaz:
npx wrangler secret put SLACK_WEBHOOK_URLEnter a secret value: https://hooks.slack.com/services/abc123Zpracování chyb
Podobně jako u lookup trasa, webhook trasa by měla obsahovat základní ošetření chyb. Na rozdíl od lookup, který odesílá odpovědi přímo zpět do Slacku, pokud se s vaším webhookem něco pokazí, může být užitečné skutečně vygenerovat chybovou odpověď a vrátit ji do GitHub.
K tomu napište vlastní obslužnou rutinu chyb pomocí app.onError() a vrátí novou odpověď se stavovým kódem 500. Finální verze src/routes/webhook.ts vypadá takto:
import { Hono } from "hono";
import { constructGhIssueSlackMessage } from "../utils/slack";
import { Bindings } from "../types";
const app = new Hono<{ Bindings: Bindings }>();
app.post("/", async (c) => {
const { action, issue, repository } = await c.req.json();
const prefix_text = `An issue was ${action}:`;
const issue_string = `${repository.owner.login}/${repository.name}#${issue.number}`;
const blocks = constructGhIssueSlackMessage(issue, issue_string, prefix_text);
const fetchResponse = await fetch(c.env.SLACK_WEBHOOK_URL, {
body: JSON.stringify({ blocks }),
method: "POST",
headers: { "Content-Type": "application/json" },
});
if (!fetchResponse.ok) throw new Error();
return c.text("OK");
});
app.onError((_e, c) => {
return c.json(
{
message: "Unable to handle webhook",
},
500,
);
});
export default app;Nasadit
Dokončením předchozích kroků jste napsali kód pro svého Slack bota. Nyní můžete aplikaci nasadit.
Wrangler má vestavěnou podporu pro bundling, nahrávání a vydávání vaší aplikace Cloudflare Workers. K tomu spusťte následující příkaz, který sestaví a nasadí váš kód.
npm i -- deployNasazení vaší aplikace Workers by nyní mělo způsobit, že se ve vašem kanálu Slack začnou zobrazovat aktualizace issues, protože webhook GitHubu se nyní může úspěšně dostat na trasu webhooku vašeho Workeru:
Související zdroje
V tomto tutoriálu jste sestavili a nasadili aplikaci Cloudflare Workers, která umí reagovat na webhook události GitHubu a umožňuje vyhledávání přes GitHub API přímo ve Slacku. Pokud si chcete prohlédnout celý zdrojový kód této aplikace, najdete repozitář na GitHubu ↗.
Pokud chcete začít vytvářet vlastní projekty, projděte si existující seznam Šablony pro rychlý start.