Allow GitHub and Slack base URLs to be overridden via env vars

Adds GITHUB_BASE_URL and SLACK_BASE_URL environment variable support
so integration tests can redirect traffic to fake servers instead of
hitting live third-party services.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-30 19:08:12 -04:00
parent 0b576079fb
commit 3a74c51840
No known key found for this signature in database
11 changed files with 34 additions and 22 deletions

View file

@ -34,7 +34,7 @@ async fn close_from(
&record.owner,
&record.repo,
record.number,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
.map_err(|err| anyhow::anyhow!("{err}"))?;

View file

@ -110,7 +110,7 @@ async fn create_from(
&owner,
&repo,
run_branch,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
.map_err(|err| anyhow::anyhow!("{err}"))?;

View file

@ -71,7 +71,7 @@ async fn list_from(
&record.owner,
&record.repo,
record.number,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
{

View file

@ -36,7 +36,7 @@ async fn merge_from(
&record.repo,
record.number,
&args.method,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
.map_err(|err| anyhow::anyhow!("{err}"))?;

View file

@ -35,7 +35,7 @@ async fn view_from(
&record.owner,
&record.repo,
record.number,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
.map_err(|err| anyhow::anyhow!("{err}"))?;

View file

@ -153,7 +153,7 @@ async fn mint_github_token(
&jwt,
&owner,
&repo,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
perms_json,
)
.await

View file

@ -206,7 +206,7 @@ async fn check_github_app_installation() {
&jwt,
&owner,
&repo,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
{
@ -229,7 +229,7 @@ async fn check_github_app_installation() {
if let Ok(app_info) = fabro_github::get_authenticated_app(
&client,
&jwt,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
{
@ -238,7 +238,7 @@ async fn check_github_app_installation() {
&& fabro_github::is_app_public(
&client,
&app_info.slug,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
== Ok(false);
@ -281,7 +281,7 @@ async fn check_github_app_installation() {
&jwt,
&owner,
&repo,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
)
.await
{

View file

@ -4,6 +4,11 @@ use serde::Deserialize;
pub const GITHUB_API_BASE_URL: &str = "https://api.github.com";
/// Returns the GitHub API base URL, allowing override via `GITHUB_BASE_URL` env var.
pub fn github_api_base_url() -> String {
std::env::var("GITHUB_BASE_URL").unwrap_or_else(|_| GITHUB_API_BASE_URL.to_string())
}
/// Detailed information about a pull request from the GitHub API.
#[derive(Debug, Clone, Deserialize)]
pub struct PullRequestDetail {
@ -409,9 +414,9 @@ pub async fn create_pull_request(
let jwt = sign_app_jwt(&creds.app_id, &creds.private_key_pem)?;
let client = reqwest::Client::new();
let base_url = github_api_base_url();
let token =
create_installation_access_token_for_pr(&client, &jwt, owner, repo, GITHUB_API_BASE_URL)
.await?;
create_installation_access_token_for_pr(&client, &jwt, owner, repo, &base_url).await?;
tracing::debug!(title = %title, head = %head, base = %base, draft, "Creating pull request");
@ -423,7 +428,7 @@ pub async fn create_pull_request(
"draft": draft,
});
let url = format!("{GITHUB_API_BASE_URL}/repos/{owner}/{repo}/pulls");
let url = format!("{base_url}/repos/{owner}/{repo}/pulls");
let auth = format!("Bearer {token}");
let resp = HttpClient::request(
&client,
@ -501,9 +506,9 @@ pub async fn enable_auto_merge(
let jwt = sign_app_jwt(&creds.app_id, &creds.private_key_pem)?;
let client = reqwest::Client::new();
let base_url = github_api_base_url();
let token =
create_installation_access_token_for_pr(&client, &jwt, owner, repo, GITHUB_API_BASE_URL)
.await?;
create_installation_access_token_for_pr(&client, &jwt, owner, repo, &base_url).await?;
let query = format!(
r#"mutation {{
@ -525,7 +530,7 @@ pub async fn enable_auto_merge(
"Enabling auto-merge"
);
let graphql_url = format!("{GITHUB_API_BASE_URL}/graphql");
let graphql_url = format!("{base_url}/graphql");
let auth = format!("Bearer {token}");
let graphql_body = serde_json::json!({ "query": query });
let resp = HttpClient::request(
@ -734,8 +739,8 @@ pub async fn resolve_clone_credentials(
let jwt = sign_app_jwt(&creds.app_id, &creds.private_key_pem)?;
let client = reqwest::Client::new();
let token =
create_installation_access_token(&client, &jwt, owner, repo, GITHUB_API_BASE_URL).await?;
let base_url = github_api_base_url();
let token = create_installation_access_token(&client, &jwt, owner, repo, &base_url).await?;
Ok((Some("x-access-token".to_string()), Some(token)))
}

View file

@ -13,13 +13,17 @@ pub struct PostedMessage {
#[derive(Clone)]
pub struct SlackClient {
bot_token: String,
api_base: String,
http: Client,
}
impl SlackClient {
pub fn new(bot_token: String) -> Self {
let api_base =
std::env::var("SLACK_BASE_URL").unwrap_or_else(|_| SLACK_API_BASE.to_string());
Self {
bot_token,
api_base,
http: Client::new(),
}
}
@ -37,7 +41,7 @@ impl SlackClient {
let body = build_post_message_body(channel, blocks, thread_ts);
let resp = self
.http
.post(format!("{SLACK_API_BASE}/chat.postMessage"))
.post(format!("{}/chat.postMessage", self.api_base))
.bearer_auth(&self.bot_token)
.json(&body)
.send()
@ -63,7 +67,7 @@ impl SlackClient {
let body = build_update_message_body(channel, ts, blocks);
let resp = self
.http
.post(format!("{SLACK_API_BASE}/chat.update"))
.post(format!("{}/chat.update", self.api_base))
.bearer_auth(&self.bot_token)
.json(&body)
.send()

View file

@ -61,7 +61,10 @@ pub async fn open_socket_url(
app_token: &str,
) -> Result<String, ConnectionError> {
let resp = http
.post("https://slack.com/api/apps.connections.open")
.post(format!(
"{}/apps.connections.open",
std::env::var("SLACK_BASE_URL").unwrap_or_else(|_| "https://slack.com/api".to_string())
))
.bearer_auth(app_token)
.header("Content-Type", "application/x-www-form-urlencoded")
.send()

View file

@ -219,7 +219,7 @@ async fn mint_github_token(
&jwt,
&owner,
&repo,
fabro_github::GITHUB_API_BASE_URL,
&fabro_github::github_api_base_url(),
perms_json,
)
.await