Skip to content

Commit b7fb41a

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 e72e200 commit b7fb41a

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
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: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,40 +134,67 @@ impl Repository {
134134
pub async fn git_auto(url: Url) -> Self {
135135
let url2 = url.clone();
136136
match (url.scheme(), url.domain()) {
137-
("http" | "https", Some("github.com")) => Self::github_from_url(url),
138-
("http" | "https", Some("gitlab.com")) => Self::gitlab_from_url(url),
139-
("http" | "https", Some("codeberg.org")) => Self::forgejo_from_url(url),
137+
("http" | "https", Some("github.com")) => {
138+
log::debug!("Trying to parse URL as GitHub repository based on the domain name (github.com)");
139+
Self::github_from_url(url)
140+
.inspect(|_| log::info!("Auto-detected GitHub repository (github.com)"))
141+
},
142+
("http" | "https", Some("gitlab.com")) => {
143+
log::debug!("Trying to parse URL as GitLab repository based on the domain name (gitlab.com)");
144+
Self::gitlab_from_url(url)
145+
.inspect(|_| log::info!("Auto-detected GitLab repository (gitlab.com)"))
146+
},
147+
("http" | "https", Some("codeberg.org")) => {
148+
log::debug!("Trying to parse URL as Forgejo repository based on the domain name (codeberg.org)");
149+
Self::forgejo_from_url(url)
150+
.inspect(|_| log::info!("Auto-detected Forgejo repository (codeberg.org)"))
151+
},
140152
("http" | "https", _) => Self::probe_forge(url).await,
141153
_ => None,
142154
}
143-
.unwrap_or(Self::git(url2))
155+
.unwrap_or_else(|| {
156+
log::info!("No forge was auto-detected, treating as plain git repository");
157+
Self::git(url2)
158+
})
144159
}
145160

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

156167
/* We probe some known endpoints unique to the respective GitLab and Forgejo APIs to determine if a corresponding server is running */
157168
let distinct_api_endpoints = [
158169
(
170+
"GitLab",
159171
"/api/v4/projects",
160172
Self::gitlab_from_url as fn(Url) -> Option<Self>,
161173
),
162174
(
175+
"Forgejo",
163176
"/api/v1/settings/api",
164177
Self::forgejo_from_url as fn(Url) -> Option<Self>,
165178
),
166179
];
167180

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

src/main.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,15 +273,19 @@ impl GitAddOpts {
273273
let name = name.strip_suffix(".git").unwrap_or(&name);
274274

275275
use git::Repository;
276-
let url2 = url.clone();
277276
let repository = match self.forge {
278-
GitForgeOpts::Auto => Some(Repository::git_auto(url).await),
279-
GitForgeOpts::None => Some(Repository::git(url)),
280-
GitForgeOpts::Github => Repository::github_from_url(url),
281-
GitForgeOpts::Gitlab => Repository::gitlab_from_url(url),
282-
GitForgeOpts::Forgejo => Repository::forgejo_from_url(url),
283-
}
284-
.unwrap_or(Repository::git(url2));
277+
GitForgeOpts::Auto => Repository::git_auto(url).await,
278+
GitForgeOpts::None => Repository::git(url),
279+
GitForgeOpts::Github => Repository::github_from_url(url).ok_or_else(|| {
280+
anyhow::format_err!("Could not parse the URL as GitHub repository")
281+
})?,
282+
GitForgeOpts::Gitlab => Repository::gitlab_from_url(url).ok_or_else(|| {
283+
anyhow::format_err!("Could not parse the URL as GitLab repository")
284+
})?,
285+
GitForgeOpts::Forgejo => Repository::forgejo_from_url(url).ok_or_else(|| {
286+
anyhow::format_err!("Could not parse the URL as Forgejo repository")
287+
})?,
288+
};
285289

286290
Ok((Some(name.to_owned()), self.more.add(repository)?))
287291
}
@@ -786,7 +790,7 @@ impl Opts {
786790
let length = if opts.names.is_empty() {
787791
pins.pins
788792
.iter()
789-
.filter(|(_, pin)| (opts.update_frozen || !pin.is_frozen()))
793+
.filter(|(_, pin)| opts.update_frozen || !pin.is_frozen())
790794
.count()
791795
} else {
792796
selected_pins.len()

0 commit comments

Comments
 (0)