diff --git a/.env.sample b/.env.sample index 5afdcbf8..d0092bd7 100644 --- a/.env.sample +++ b/.env.sample @@ -11,3 +11,13 @@ GITHUB_WEBHOOK_SECRET=MUST_BE_CONFIGURED # For example write blahblahblah here, if you want for this bot to # respond to @blahblahblah claim. # TRIAGEBOT_USERNAME=CAN_BE_CONFIGURED + +# Set your own Zulip instance (local testing only) +# ZULIP_URL=https://testinstance.zulichat.com + +# Used for authenticating a bot +# ZULIP_BOT_EMAIL=bot@testinstance.zulipchat.com +# ZULIP_API_TOKEN=yyy + +# Authenticates inbound webhooks from Github +# ZULIP_TOKEN=xxx \ No newline at end of file diff --git a/README.md b/README.md index 436926bf..814b036f 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,10 @@ gh webhook forward --repo=ehuss/triagebot-test --events=* \ Where the value in `--secret` is the secret value you place in `GITHUB_WEBHOOK_SECRET` in the `.env` file, and `--repo` is the repo you want to test against. +### Zulip testing + +If you are modifying code that sends message to Zulip and want to test your changes, you can register a [new free Zulip instance](https://zulip.com/new/). Before launching the triagebot locally, set the Zulip env vars to connect to your test instance (see example in `.env.sample`). + #### ngrok The following is an example of using to provide webhook forwarding. diff --git a/src/zulip.rs b/src/zulip.rs index 8e77ab82..615670f8 100644 --- a/src/zulip.rs +++ b/src/zulip.rs @@ -9,8 +9,12 @@ use anyhow::{format_err, Context as _}; use std::env; use std::fmt::Write as _; use std::str::FromStr; +use std::sync::LazyLock; use tracing as log; +static ZULIP_URL: LazyLock = + LazyLock::new(|| env::var("ZULIP_URL").unwrap_or("https://rust-lang.zulipchat.com".into())); + #[derive(Debug, serde::Deserialize)] pub struct Request { /// Markdown body of the sent message. @@ -71,8 +75,6 @@ struct Response { content: String, } -pub const BOT_EMAIL: &str = "triage-rust-lang-bot@zulipchat.com"; - pub async fn to_github_id(client: &GithubClient, zulip_id: u64) -> anyhow::Result> { let map = crate::team_data::zulip_map(client).await?; Ok(map.users.get(&zulip_id).copied()) @@ -295,12 +297,14 @@ async fn execute_for_other_user( command }; let bot_api_token = env::var("ZULIP_API_TOKEN").expect("ZULIP_API_TOKEN"); + let bot_email = + env::var("ZULIP_BOT_EMAIL").unwrap_or("triage-rust-lang-bot@zulipchat.com".into()); let members = ctx .github .raw() - .get("https://rust-lang.zulipchat.com/api/v1/users") - .basic_auth(BOT_EMAIL, Some(&bot_api_token)) + .get(format!("{}/api/v1/users", *ZULIP_URL)) + .basic_auth(bot_email, Some(&bot_api_token)) .send() .await .map_err(|e| format_err!("Failed to get list of zulip users: {e:?}."))?; @@ -414,7 +418,7 @@ impl Recipient<'_> { } pub fn url(&self) -> String { - format!("https://rust-lang.zulipchat.com/#narrow/{}", self.narrow()) + format!("{}/#narrow/{}", *ZULIP_URL, self.narrow()) } } @@ -458,6 +462,8 @@ impl<'a> MessageApiRequest<'a> { pub async fn send(&self, client: &reqwest::Client) -> anyhow::Result { let bot_api_token = env::var("ZULIP_API_TOKEN").expect("ZULIP_API_TOKEN"); + let bot_email = + env::var("ZULIP_BOT_EMAIL").unwrap_or("triage-rust-lang-bot@zulipchat.com".into()); #[derive(serde::Serialize)] struct SerializedApi<'a> { @@ -470,8 +476,8 @@ impl<'a> MessageApiRequest<'a> { } Ok(client - .post("https://rust-lang.zulipchat.com/api/v1/messages") - .basic_auth(BOT_EMAIL, Some(&bot_api_token)) + .post(format!("{}/api/v1/messages", *ZULIP_URL)) + .basic_auth(bot_email, Some(&bot_api_token)) .form(&SerializedApi { type_: match self.recipient { Recipient::Stream { .. } => "stream", @@ -509,6 +515,8 @@ pub struct UpdateMessageApiRequest<'a> { impl<'a> UpdateMessageApiRequest<'a> { pub async fn send(&self, client: &reqwest::Client) -> anyhow::Result { let bot_api_token = env::var("ZULIP_API_TOKEN").expect("ZULIP_API_TOKEN"); + let bot_email = + env::var("ZULIP_BOT_EMAIL").unwrap_or("triage-rust-lang-bot@zulipchat.com".into()); #[derive(serde::Serialize)] struct SerializedApi<'a> { @@ -522,10 +530,10 @@ impl<'a> UpdateMessageApiRequest<'a> { Ok(client .patch(&format!( - "https://rust-lang.zulipchat.com/api/v1/messages/{}", - self.message_id + "{}/api/v1/messages/{}", + *ZULIP_URL, self.message_id )) - .basic_auth(BOT_EMAIL, Some(&bot_api_token)) + .basic_auth(bot_email, Some(&bot_api_token)) .form(&SerializedApi { topic: self.topic, propagate_mode: self.propagate_mode, @@ -712,13 +720,15 @@ struct AddReaction<'a> { impl<'a> AddReaction<'a> { pub async fn send(self, client: &reqwest::Client) -> anyhow::Result { let bot_api_token = env::var("ZULIP_API_TOKEN").expect("ZULIP_API_TOKEN"); + let bot_email = + env::var("ZULIP_BOT_EMAIL").unwrap_or("triage-rust-lang-bot@zulipchat.com".into()); Ok(client .post(&format!( - "https://rust-lang.zulipchat.com/api/v1/messages/{}/reactions", - self.message_id + "{}/api/v1/messages/{}/reactions", + *ZULIP_URL, self.message_id )) - .basic_auth(BOT_EMAIL, Some(&bot_api_token)) + .basic_auth(bot_email, Some(&bot_api_token)) .form(&self) .send() .await?)