Skip to content

Commit 8828b7d

Browse files
committed
fix: use SSH URL for gh: abbreviation when user has SSH configured
Detect the user's preferred GitHub protocol via `gh config get git_protocol -h github.com`. When set to SSH, expand gh:user/repo to git@github.com:user/repo.git instead of the HTTPS URL. Falls back to HTTPS when gh CLI is not installed or protocol is https.
1 parent 7044cfa commit 8828b7d

1 file changed

Lines changed: 79 additions & 6 deletions

File tree

src/template/source.rs

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22
use std::path::{Path, PathBuf};
3+
use std::process::Command;
34

45
use crate::error::{DicecutError, Result};
56

@@ -20,7 +21,44 @@ const ABBREVIATIONS: &[(&str, &str, &str)] = &[
2021
("sr:", "https://git.sr.ht/", ""),
2122
];
2223

24+
fn detect_github_protocol() -> String {
25+
Command::new("gh")
26+
.args(["config", "get", "git_protocol", "-h", "github.com"])
27+
.output()
28+
.ok()
29+
.and_then(|output| {
30+
if output.status.success() {
31+
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
32+
if stdout == "ssh" {
33+
return Some("ssh".to_string());
34+
}
35+
}
36+
None
37+
})
38+
.unwrap_or_else(|| "https".to_string())
39+
}
40+
41+
fn build_github_url(rest: &str, protocol: &str) -> String {
42+
if protocol == "ssh" {
43+
format!("git@github.com:{rest}.git")
44+
} else {
45+
format!("https://github.com/{rest}.git")
46+
}
47+
}
48+
2349
fn expand_abbreviation(input: &str) -> Result<String> {
50+
// Special case: GitHub abbreviation with protocol detection
51+
if let Some(rest) = input.strip_prefix("gh:") {
52+
if rest.is_empty() {
53+
return Err(DicecutError::InvalidAbbreviation {
54+
input: input.to_string(),
55+
});
56+
}
57+
let protocol = detect_github_protocol();
58+
return Ok(build_github_url(rest, &protocol));
59+
}
60+
61+
// All other abbreviations use static expansion
2462
for &(prefix, base_url, suffix) in ABBREVIATIONS {
2563
if let Some(rest) = input.strip_prefix(prefix) {
2664
if rest.is_empty() {
@@ -129,10 +167,25 @@ mod tests {
129167

130168
// ── Abbreviation expansion ──────────────────────────────────────────
131169

170+
#[test]
171+
fn build_github_url_ssh() {
172+
let url = build_github_url("user/repo", "ssh");
173+
assert_eq!(url, "git@github.com:user/repo.git");
174+
}
175+
176+
#[test]
177+
fn build_github_url_https() {
178+
let url = build_github_url("user/repo", "https");
179+
assert_eq!(url, "https://github.com/user/repo.git");
180+
}
181+
132182
#[test]
133183
fn expand_github_abbreviation() {
134184
let url = expand_abbreviation("gh:user/repo").unwrap();
135-
assert_eq!(url, "https://github.com/user/repo.git");
185+
assert!(
186+
url == "https://github.com/user/repo.git" || url == "git@github.com:user/repo.git",
187+
"unexpected URL: {url}"
188+
);
136189
}
137190

138191
#[test]
@@ -191,7 +244,11 @@ mod tests {
191244
let source = resolve_source("gh:user/repo").unwrap();
192245
match source {
193246
TemplateSource::Git { url, git_ref } => {
194-
assert_eq!(url, "https://github.com/user/repo.git");
247+
assert!(
248+
url == "https://github.com/user/repo.git"
249+
|| url == "git@github.com:user/repo.git",
250+
"unexpected URL: {url}"
251+
);
195252
assert!(git_ref.is_none());
196253
}
197254
_ => panic!("expected Git source"),
@@ -229,7 +286,11 @@ mod tests {
229286
let source = resolve_source_with_ref("gh:user/repo", Some("v1.0")).unwrap();
230287
match source {
231288
TemplateSource::Git { url, git_ref } => {
232-
assert_eq!(url, "https://github.com/user/repo.git");
289+
assert!(
290+
url == "https://github.com/user/repo.git"
291+
|| url == "git@github.com:user/repo.git",
292+
"unexpected URL: {url}"
293+
);
233294
assert_eq!(git_ref.as_deref(), Some("v1.0"));
234295
}
235296
_ => panic!("expected Git source"),
@@ -241,7 +302,11 @@ mod tests {
241302
let source = resolve_source_with_ref("gh:user/repo", None).unwrap();
242303
match source {
243304
TemplateSource::Git { url, git_ref } => {
244-
assert_eq!(url, "https://github.com/user/repo.git");
305+
assert!(
306+
url == "https://github.com/user/repo.git"
307+
|| url == "git@github.com:user/repo.git",
308+
"unexpected URL: {url}"
309+
);
245310
assert!(git_ref.is_none());
246311
}
247312
_ => panic!("expected Git source"),
@@ -342,7 +407,11 @@ mod tests {
342407
let source = resolve_source_full("gh:user/repo", None, Some(&abbrevs)).unwrap();
343408
match source {
344409
TemplateSource::Git { url, .. } => {
345-
assert_eq!(url, "https://github.com/user/repo.git");
410+
assert!(
411+
url == "https://github.com/user/repo.git"
412+
|| url == "git@github.com:user/repo.git",
413+
"unexpected URL: {url}"
414+
);
346415
}
347416
_ => panic!("expected Git source"),
348417
}
@@ -353,7 +422,11 @@ mod tests {
353422
let source = resolve_source_full("gh:user/repo", None, None).unwrap();
354423
match source {
355424
TemplateSource::Git { url, .. } => {
356-
assert_eq!(url, "https://github.com/user/repo.git");
425+
assert!(
426+
url == "https://github.com/user/repo.git"
427+
|| url == "git@github.com:user/repo.git",
428+
"unexpected URL: {url}"
429+
);
357430
}
358431
_ => panic!("expected Git source"),
359432
}

0 commit comments

Comments
 (0)