Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/auth/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::auth::AuthSource;
use crate::error::{Error, Result};
use crate::types::normalize_host;
use reqwest::Client;
use serde::Deserialize;
use std::env;
Expand All @@ -27,8 +28,8 @@ pub struct GitLabAuthConfig {
/// 3. `GL_TOKEN` environment variable
pub async fn get_gitlab_auth(host: Option<&str>) -> Result<GitLabAuthConfig> {
let host = host
.map(String::from)
.or_else(|| env::var("GITLAB_HOST").ok())
.map(normalize_host)
.or_else(|| env::var("GITLAB_HOST").ok().map(|h| normalize_host(&h)))
.unwrap_or_else(|| "gitlab.com".to_string());

// Try glab CLI first
Expand Down
6 changes: 3 additions & 3 deletions src/platform/detection.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Platform detection from remote URLs

use crate::error::{Error, Result};
use crate::types::{Platform, PlatformConfig};
use crate::types::{Platform, PlatformConfig, normalize_host};
use regex::Regex;
use std::env;
use std::sync::LazyLock;
Expand All @@ -16,8 +16,8 @@ static RE_HTTPS: LazyLock<Regex> =

/// Detect platform (GitHub or GitLab) from a remote URL
pub fn detect_platform(url: &str) -> Option<Platform> {
let gh_host = env::var("GH_HOST").ok();
let gitlab_host = env::var("GITLAB_HOST").ok();
let gh_host = env::var("GH_HOST").ok().map(|h| normalize_host(&h));
let gitlab_host = env::var("GITLAB_HOST").ok().map(|h| normalize_host(&h));

let hostname = extract_hostname(url)?;

Expand Down
3 changes: 2 additions & 1 deletion src/platform/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::error::{Error, Result};
use crate::platform::PlatformService;
use crate::types::{Platform, PlatformConfig, PrComment, PullRequest};
use crate::types::{Platform, PlatformConfig, PrComment, PullRequest, normalize_host};
use async_trait::async_trait;
use octocrab::Octocrab;
use serde::Deserialize;
Expand Down Expand Up @@ -68,6 +68,7 @@ pub struct GitHubService {
impl GitHubService {
/// Create a new GitHub service
pub fn new(token: &str, owner: String, repo: String, host: Option<String>) -> Result<Self> {
let host = host.map(|h| normalize_host(&h));
let mut builder = Octocrab::builder().personal_token(token.to_string());

if let Some(ref h) = host {
Expand Down
4 changes: 2 additions & 2 deletions src/platform/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::error::{Error, Result};
use crate::platform::PlatformService;
use crate::types::{Platform, PlatformConfig, PrComment, PullRequest};
use crate::types::{Platform, PlatformConfig, PrComment, PullRequest, normalize_host};
use async_trait::async_trait;
use reqwest::Client;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -64,7 +64,7 @@ const DEFAULT_TIMEOUT_SECS: u64 = 30;
impl GitLabService {
/// Create a new GitLab service
pub fn new(token: String, owner: String, repo: String, host: Option<String>) -> Result<Self> {
let host = host.unwrap_or_else(|| "gitlab.com".to_string());
let host = host.map_or_else(|| "gitlab.com".to_string(), |h| normalize_host(&h));
let project_path = format!("{owner}/{repo}");

let client = Client::builder()
Expand Down
27 changes: 27 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,30 @@ pub struct PlatformConfig {
/// Custom host (None for github.com/gitlab.com)
pub host: Option<String>,
}

/// Normalize a host value by stripping any protocol prefix and trailing slashes.
///
/// This handles cases where users provide a full URL (e.g., `https://gitlab.example.com/`)
/// instead of a bare hostname (e.g., `gitlab.example.com`).
///
/// # Examples
///
/// ```
/// use jj_ryu::normalize_host;
///
/// assert_eq!(normalize_host("gitlab.com"), "gitlab.com");
/// assert_eq!(normalize_host("https://gitlab.com"), "gitlab.com");
/// assert_eq!(normalize_host("http://gitlab.com/"), "gitlab.com");
/// assert_eq!(normalize_host("https://gitlab.example.com/some/path"), "gitlab.example.com");
/// ```
#[must_use]
pub fn normalize_host(host: &str) -> String {
let host = host
.trim()
.trim_start_matches("https://")
.trim_start_matches("http://");

let host = host.split('/').next().unwrap_or(host);

host.to_string()
}
60 changes: 60 additions & 0 deletions tests/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,66 @@ mod analysis_test {
}
}

mod normalize_host_test {
use jj_ryu::normalize_host;

#[test]
fn test_bare_hostname_unchanged() {
assert_eq!(normalize_host("gitlab.com"), "gitlab.com");
assert_eq!(
normalize_host("github.enterprise.com"),
"github.enterprise.com"
);
}

#[test]
fn test_strips_https_protocol() {
assert_eq!(normalize_host("https://gitlab.com"), "gitlab.com");
assert_eq!(
normalize_host("https://gitlab.example.com"),
"gitlab.example.com"
);
}

#[test]
fn test_strips_http_protocol() {
assert_eq!(normalize_host("http://gitlab.com"), "gitlab.com");
assert_eq!(
normalize_host("http://gitlab.example.com"),
"gitlab.example.com"
);
}

#[test]
fn test_strips_trailing_slash() {
assert_eq!(normalize_host("gitlab.com/"), "gitlab.com");
assert_eq!(normalize_host("https://gitlab.com/"), "gitlab.com");
}

#[test]
fn test_strips_path() {
assert_eq!(normalize_host("https://gitlab.com/some/path"), "gitlab.com");
assert_eq!(normalize_host("gitlab.com/api/v4"), "gitlab.com");
}

#[test]
fn test_strips_whitespace() {
assert_eq!(normalize_host(" gitlab.com "), "gitlab.com");
assert_eq!(normalize_host(" https://gitlab.com "), "gitlab.com");
}
#[test]
fn test_github_enterprise_host() {
assert_eq!(
normalize_host("https://github.mycompany.com"),
"github.mycompany.com"
);
assert_eq!(
normalize_host("github.mycompany.com"),
"github.mycompany.com"
);
}
}

mod detection_test {
use jj_ryu::error::Error;
use jj_ryu::platform::{detect_platform, parse_repo_info};
Expand Down