Skip to content

Commit 397193a

Browse files
committed
git forge auto-detection: Streamline user experience
- Added a log message for the detected forge type, and debug log messages to make it easier to figure out what is happening when auto-detection fails - When explicitly specifying a forge via `--forge`, auto-detection failures are a hard error instead of falling back to generic git forges
1 parent c081c38 commit 397193a

File tree

3 files changed

+50
-20
lines changed

3 files changed

+50
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- `npins show` now accepts a list of pin entries to show instead of always showing the complete list (https://github.com/andir/npins/pull/190)
6+
- Tweaked forge auto-detection for `git add` (https://github.com/andir/npins/pull/202)
67

78
## 0.4.0
89

libnpins/src/git.rs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,40 +136,65 @@ impl Repository {
136136
pub async fn git_auto(url: Url) -> Self {
137137
let url2 = url.clone();
138138
match (url.scheme(), url.domain()) {
139-
("http" | "https", Some("github.com")) => Self::github_from_url(url),
140-
("http" | "https", Some("gitlab.com")) => Self::gitlab_from_url(url),
141-
("http" | "https", Some("codeberg.org")) => Self::forgejo_from_url(url),
139+
("http" | "https", Some("github.com")) => {
140+
log::debug!("Trying to parse URL as GitHub repository based on the domain name (github.com)");
141+
Self::github_from_url(url)
142+
.inspect(|_| log::info!("Auto-detected GitHub repository (github.com)"))
143+
},
144+
("http" | "https", Some("gitlab.com")) => {
145+
log::debug!("Trying to parse URL as GitLab repository based on the domain name (gitlab.com)");
146+
Self::gitlab_from_url(url)
147+
.inspect(|_| log::info!("Auto-detected GitLab repository (gitlab.com)"))
148+
},
149+
("http" | "https", Some("codeberg.org")) => {
150+
log::debug!("Trying to parse URL as Forgejo repository based on the domain name (codeberg.org)");
151+
Self::forgejo_from_url(url)
152+
.inspect(|_| log::info!("Auto-detected Forgejo repository (codeberg.org)"))
153+
},
142154
("http" | "https", _) => Self::probe_forge(url).await,
143155
_ => None,
144156
}
145-
.unwrap_or(Self::git(url2))
157+
.unwrap_or_else(|| {
158+
log::info!("No forge was auto-detected, treating as plain git repository");
159+
Self::git(url2)
160+
})
146161
}
147162

148163
///
149164
/// Takes in a URL of unknown forge and tries to determine which forge the hoster is
150165
/// And then parse the url into the according Repository Variant
151166
async fn probe_forge(url: Url) -> Option<Self> {
152-
async fn probe(mut test_url: Url, path: &str) -> Result<()> {
153-
test_url.set_path(path);
154-
let _: serde_json::Value = get_and_deserialize(test_url).await?;
155-
Ok(())
156-
}
167+
log::debug!("Probing {url} for Forgejo and GitLab API endpoints");
157168

158169
/* We probe some known endpoints unique to the respective GitLab and Forgejo APIs to determine if a corresponding server is running */
159170
let distinct_api_endpoints = [
160171
(
172+
"GitLab",
161173
"/api/v4/projects",
162174
Self::gitlab_from_url as fn(Url) -> Option<Self>,
163175
),
164176
(
177+
"Forgejo",
165178
"/api/v1/settings/api",
166179
Self::forgejo_from_url as fn(Url) -> Option<Self>,
167180
),
168181
];
169182

170-
for (path, func) in distinct_api_endpoints {
171-
if probe(url.clone(), path).await.is_ok() {
172-
return func(url);
183+
for (forge_type, path, func) in distinct_api_endpoints {
184+
let probe = |mut test_url: Url| async {
185+
test_url.set_path(path);
186+
log::debug!("Probing {test_url} to check for {forge_type}");
187+
let _: serde_json::Value = get_and_deserialize(test_url).await?;
188+
Ok::<(), anyhow::Error>(())
189+
};
190+
191+
if probe(url.clone()).await.is_ok() {
192+
return func(url.clone()).inspect(|_| {
193+
log::info!(
194+
"Auto-detected {forge_type} repository ({})",
195+
url.domain().unwrap()
196+
)
197+
})
173198
}
174199
}
175200
None

src/main.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -280,15 +280,19 @@ impl GitAddOpts {
280280
let name = name.strip_suffix(".git").unwrap_or(&name);
281281

282282
use git::Repository;
283-
let url2 = url.clone();
284283
let repository = match self.forge {
285-
GitForgeOpts::Auto => Some(Repository::git_auto(url).await),
286-
GitForgeOpts::None => Some(Repository::git(url)),
287-
GitForgeOpts::Github => Repository::github_from_url(url),
288-
GitForgeOpts::Gitlab => Repository::gitlab_from_url(url),
289-
GitForgeOpts::Forgejo => Repository::forgejo_from_url(url),
290-
}
291-
.unwrap_or(Repository::git(url2));
284+
GitForgeOpts::Auto => Repository::git_auto(url).await,
285+
GitForgeOpts::None => Repository::git(url),
286+
GitForgeOpts::Github => Repository::github_from_url(url).ok_or_else(|| {
287+
anyhow::format_err!("Could not parse the URL as GitHub repository")
288+
})?,
289+
GitForgeOpts::Gitlab => Repository::gitlab_from_url(url).ok_or_else(|| {
290+
anyhow::format_err!("Could not parse the URL as GitLab repository")
291+
})?,
292+
GitForgeOpts::Forgejo => Repository::forgejo_from_url(url).ok_or_else(|| {
293+
anyhow::format_err!("Could not parse the URL as Forgejo repository")
294+
})?,
295+
};
292296

293297
Ok((Some(name.to_owned()), self.more.add(repository)?))
294298
}

0 commit comments

Comments
 (0)