Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(git): find upstream remote when using ssh #926

Merged
merged 3 commits into from
Oct 21, 2024
Merged
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
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Note that we have a [Code of Conduct](./CODE_OF_CONDUCT.md), please follow it in

```sh
git clone https://github.com/{username}/git-cliff && cd git-cliff
# OR
git clone [email protected]:{username}/git-cliff && cd git-cliff
```

To ensure the successful execution of the tests, it is essential to fetch the tags as follows:
Expand Down
107 changes: 88 additions & 19 deletions git-cliff-core/src/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ impl Repository {
///
/// Find the branch that HEAD points to, and read the remote configured for
/// that branch returns the remote and the name of the local branch.
///
/// Note: HEAD must not be detached.
pub fn upstream_remote(&self) -> Result<Remote> {
for branch in self.inner.branches(Some(BranchType::Local))? {
let branch = branch?.0;
Expand All @@ -424,30 +426,79 @@ impl Repository {
})?
.to_string();
trace!("Upstream URL: {url}");
let url = Url::parse(&url)?;
let segments: Vec<&str> = url
.path_segments()
.ok_or_else(|| {
Error::RepoError(String::from("failed to get URL segments"))
})?
.rev()
.collect();
if let (Some(owner), Some(repo)) =
(segments.get(1), segments.first())
{
return Ok(Remote {
owner: owner.to_string(),
repo: repo.trim_end_matches(".git").to_string(),
token: None,
is_custom: false,
});
}
return find_remote(&url);
}
}
Err(Error::RepoError(String::from("no remotes configured")))
Err(Error::RepoError(String::from(
"no remotes configured or HEAD is detached",
)))
}
}

fn find_remote(url: &str) -> Result<Remote> {
url_path_segments(url).or_else(|err| {
if url.contains("@") && url.contains(":") && url.contains("/") {
ssh_path_segments(url)
} else {
Err(err)
}
})
}

/// Returns the Remote from parsing the HTTPS format URL.
///
/// This function expects the URL to be in the following format:
///
/// > https://hostname/query/path.git
fn url_path_segments(url: &str) -> Result<Remote> {
let parsed_url = Url::parse(url.strip_suffix(".git").unwrap_or(url))?;
let segments: Vec<&str> = parsed_url
.path_segments()
.ok_or_else(|| Error::RepoError(String::from("failed to get URL segments")))?
.rev()
.collect();
let [repo, owner, ..] = &segments[..] else {
return Err(Error::RepoError(String::from(
"failed to get the owner and repo",
)));
};
Ok(Remote {
owner: owner.to_string(),
repo: repo.to_string(),
token: None,
is_custom: false,
})
}

/// Returns the Remote from parsing the SSH format URL.
///
/// This function expects the URL to be in the following format:
///
/// > git@hostname:owner/repo.git
fn ssh_path_segments(url: &str) -> Result<Remote> {
let [_, owner_repo, ..] = url
.strip_suffix(".git")
.unwrap_or(url)
.split(":")
.collect::<Vec<_>>()[..]
else {
return Err(Error::RepoError(String::from(
"failed to get the owner and repo from ssh remote (:)",
)));
};
let [owner, repo] = owner_repo.split("/").collect::<Vec<_>>()[..] else {
return Err(Error::RepoError(String::from(
"failed to get the owner and repo from ssh remote (/)",
)));
};
Ok(Remote {
owner: owner.to_string(),
repo: repo.to_string(),
token: None,
is_custom: false,
})
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -502,6 +553,24 @@ mod test {
)
}

#[test]
fn http_url_repo_owner() -> Result<()> {
let url = "https://hostname.com/bob/magic.git";
let remote = find_remote(url)?;
assert_eq!(remote.owner, "bob", "match owner");
assert_eq!(remote.repo, "magic", "match repo");
Ok(())
}

#[test]
fn ssh_url_repo_owner() -> Result<()> {
let url = "[email protected]:bob/magic.git";
let remote = find_remote(url)?;
assert_eq!(remote.owner, "bob", "match owner");
assert_eq!(remote.repo, "magic", "match repo");
Ok(())
}

#[test]
fn get_latest_commit() -> Result<()> {
let repository = get_repository()?;
Expand Down
Loading