diff --git a/.github/assets/msrv-badge.svg b/.github/assets/msrv-badge.svg
index e704d19..8345640 100644
--- a/.github/assets/msrv-badge.svg
+++ b/.github/assets/msrv-badge.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e6bb345..ccb0cc2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,12 +1,12 @@
name: CI
on:
- push:
+ merge_group:
branches:
- - staging
- - trying
+ - main
pull_request:
- branches: [main]
+ branches:
+ - main
workflow_dispatch:
env:
@@ -15,9 +15,10 @@ env:
jobs:
ci:
name: CI
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
strategy:
matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
cargo_checks:
- name: Enforce default cargo fmt
subcommand: fmt -- --check
@@ -28,29 +29,27 @@ jobs:
- name: Build
subcommand: build --release --all-features --verbose
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Stable with rustfmt and clippy
- uses: actions-rs/toolchain@v1
+ uses: dtolnay/rust-toolchain@stable
with:
- profile: minimal
- toolchain: stable
components: rustfmt, clippy
- - uses: Swatinem/rust-cache@v1
+ - uses: Swatinem/rust-cache@v2
- name: cargo check - ${{ matrix.cargo_checks.name }}
run: cargo ${{ matrix.cargo_checks.subcommand }}
- update-project-stuff:
- if: github.event_name == 'push' && github.ref == 'refs/heads/staging'
- uses: ./.github/workflows/update-repo-stuff.yml
- secrets: inherit
+ #update-project-stuff:
+ # if: github.event_name == 'push' && github.ref == 'refs/heads/staging'
+ # uses: ./.github/workflows/update-repo-stuff.yml
+ # secrets: inherit
- done:
- name: Done
- if: github.event_name == 'push' && github.ref == 'refs/heads/staging'
- needs:
- - ci
- - update-project-stuff
- runs-on: ubuntu-latest
- steps:
- - name: Done
- run: echo "Done!"
+ #done:
+ # name: Done
+ # if: github.event_name == 'push' && github.ref == 'refs/heads/staging'
+ # needs:
+ # - ci
+ # - update-project-stuff
+ # runs-on: ubuntu-latest
+ # steps:
+ # - name: Done
+ # run: echo "Done!"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2be4028..3c2dd3b 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -10,11 +10,8 @@ jobs:
name: Publish to crates.io
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- override: true
- - uses: katyo/publish-crates@v1
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
+ - uses: katyo/publish-crates@v2
with:
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf49357..70b5096 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [UNRELEASED]
+## [0.4.5](https://github.com/tjtelan/git-url-parse-rs/tree/v0.4.5) - 2024-09-06
+
+### CI
+
+- Update changelog
+
+### Changed
+
+- Update MSRV badge
+- Update README badges
+
+### Fixed
+
+- Add test for #51
+
+### Other
+
+- Reduce required dependencies
+
+## [0.4.4](https://github.com/tjtelan/git-url-parse-rs/tree/v0.4.4) - 2022-11-05
### Fixed
@@ -54,13 +73,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Other
-- Loosens dependency restrictions ([#12](https://github.com/tjtelan/git-url-parse-rs/issues/12)) ([#13](https://github.com/tjtelan/git-url-parse-rs/issues/13))
- Ci tune ([#18](https://github.com/tjtelan/git-url-parse-rs/issues/18))
### Removed
- Update dependencies and readme ([#23](https://github.com/tjtelan/git-url-parse-rs/issues/23))
+## [0.4.0](https://github.com/tjtelan/git-url-parse-rs/tree/v0.4.0) - 2021-11-14
+
+### Added
+
+- Adding release dates in changelog
+- Rename workflow + add workflow_dispatch to ci
+
+## [0.3.1](https://github.com/tjtelan/git-url-parse-rs/tree/v0.3.1) - 2021-01-27
+
+### CI
+
+- Updating Changelog to prepare for v0.3.1
+
+### Other
+
+- Loosens dependency restrictions ([#12](https://github.com/tjtelan/git-url-parse-rs/issues/12)) ([#13](https://github.com/tjtelan/git-url-parse-rs/issues/13))
+
+## [0.3.0](https://github.com/tjtelan/git-url-parse-rs/tree/v0.3.0) - 2020-10-02
+
+### Added
+
+- Adding schemas
+
## [0.2.0](https://github.com/tjtelan/git-url-parse-rs/tree/v0.2.0) - 2020-05-13
### Added
diff --git a/Cargo.toml b/Cargo.toml
index 4b6c907..9d7480d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,15 +9,18 @@ license = "MIT"
name = "git-url-parse"
readme = "README.md"
repository = "https://github.com/tjtelan/git-url-parse-rs"
-version = "0.4.4"
+version = "0.4.5"
+
+[features]
+default = []
+tracing = ["dep:tracing"]
[dependencies]
-tracing = "0.1"
-url = "^2.2"
-strum = "^0.24"
-strum_macros = "^0.24"
-color-eyre = "^0.6"
-regex = "^1.4"
+tracing = { version = "0.1", optional = true }
+url = { version = "^2.2", default-features = false }
+strum = { version = "^0.26", features = ["derive"] }
+thiserror = "^1.0"
[dev-dependencies]
env_logger = "^0.9"
+regex = "^1.10"
diff --git a/README.md b/README.md
index 1114ebf..b177a7c 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,10 @@

[](https://crates.io/crates/git-url-parse)
-
-[](https://github.com/tjtelan/git-url-parse-rs/actions/workflows/rust.yml)
+[](https://github.com/tjtelan/git-url-parse-rs/actions/workflows/ci.yml)
[](https://docs.rs/git-url-parse/)
-[](LICENSE)
-
+[](LICENSE)
+
Supports common protocols as specified by the [Pro Git book](https://git-scm.com/book/en/v2)
diff --git a/bors.toml b/bors.toml
deleted file mode 100644
index 450460e..0000000
--- a/bors.toml
+++ /dev/null
@@ -1,6 +0,0 @@
-status = [
- "Done",
-]
-use_squash_merge = true
-delete_merged_branches = true
-timeout_sec = 900 # 15 mins
\ No newline at end of file
diff --git a/cliff.toml b/cliff.toml
index 1a027e2..347c148 100644
--- a/cliff.toml
+++ b/cliff.toml
@@ -17,7 +17,11 @@ body = """
{% else %}\
## [UNRELEASED]
{% endif %}\
-{% for group, commits in commits | group_by(attribute="group") %}
+
+{% for group, commits in commits
+ | filter(attribute="merge_commit", value=false)
+ | unique(attribute="message")
+ | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message | upper_first | split(pat="\n") | first }}\
@@ -33,49 +37,49 @@ footer = """
[git]
# parse the commits based on https://www.conventionalcommits.org
-conventional_commits = true
+conventional_commits = true
# filter out the commits that are not conventional
-filter_unconventional = false
+filter_unconventional = false
commit_preprocessors = [
- { pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/tjtelan/git-url-parse-rs/issues/${1}))"}
+ { pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/tjtelan/git-url-parse-rs/issues/${1}))" },
]
# regex for parsing and grouping commits
commit_parsers = [
- { message = ".*[Bb]ump", group = "Noise", skip = true},
- { message = ".*[Rr]evert", group = "Noise", skip = true},
- { message = ".*[Cl]ippy", group = "Noise", skip = true},
- { message = "^Merge pull request", group = "Noise", skip = true},
+ { message = ".*[Bb]ump", group = "Noise", skip = true },
+ { message = ".*[Rr]evert", group = "Noise", skip = true },
+ { message = ".*[Cl]ippy", group = "Noise", skip = true },
+ { message = "^Merge pull request", group = "Noise", skip = true },
- { message = "^test", group = "Fixed"},
- { message = "^.*[Ff]ix", group = "Fixed"},
- { message = "^[Rr]esolve", group = "Fixed"},
+ { message = "^test", group = "Fixed" },
+ { message = "^.*[Ff]ix", group = "Fixed" },
+ { message = "^[Rr]esolve", group = "Fixed" },
- { message = "[Cc]ompile", group = "CI"},
- { message = "[Pp]ublish", group = "CI"},
+ { message = "[Cc]ompile", group = "CI" },
+ { message = "[Pp]ublish", group = "CI" },
- { message = ".*[Dd]eprecate", group = "Removed"},
- { message = "^[Dd]isable", group = "Removed"},
+ { message = ".*[Dd]eprecate", group = "Removed" },
+ { message = "^[Dd]isable", group = "Removed" },
- { message = ".*[Aa]dd", group = "Added"},
- { message = ".*[Ss]upport", group = "Added"},
- { message = ".*[Mm]ake", group = "Added"},
+ { message = ".*[Aa]dd", group = "Added" },
+ { message = ".*[Ss]upport", group = "Added" },
+ { message = ".*[Mm]ake", group = "Added" },
- { message = ".*[Rr]emove", group = "Removed"},
- { message = ".*[Dd]elete", group = "Removed"},
- { message = ".*[Dd]isable", group = "Removed"},
+ { message = ".*[Rr]emove", group = "Removed" },
+ { message = ".*[Dd]elete", group = "Removed" },
+ { message = ".*[Dd]isable", group = "Removed" },
- { message = "[Rr]elease", group = "CI"},
- { message = ".*[Ll]og", group = "CI"},
- { message = ".*[Bb]uild", group = "CI"},
+ { message = "[Rr]elease", group = "CI" },
+ { message = ".*[Ll]og", group = "CI" },
+ { message = ".*[Bb]uild", group = "CI" },
- { message = ".*[Uu]pdate", group = "Changed"},
+ { message = ".*[Uu]pdate", group = "Changed" },
- { message = ".*[Cc]lean", group = "Other"},
- { message = ".*[Rr]efactor", group = "Other"},
- { message = "^.*", group = "Other"},
+ { message = ".*[Cc]lean", group = "Other" },
+ { message = ".*[Rr]efactor", group = "Other" },
+ { message = "^.*", group = "Other" },
]
# filter out the commits that are not matched by commit parsers
diff --git a/examples/multi.rs b/examples/multi.rs
index 4cc9d44..33b7bd9 100644
--- a/examples/multi.rs
+++ b/examples/multi.rs
@@ -1,7 +1,6 @@
-use color_eyre::Result;
-use git_url_parse::GitUrl;
+use git_url_parse::{GitUrl, GitUrlParseError};
-fn main() -> Result<()> {
+fn main() -> Result<(), GitUrlParseError> {
env_logger::init();
let test_vec = vec![
diff --git a/examples/trim_auth.rs b/examples/trim_auth.rs
index 1b85967..8865c33 100644
--- a/examples/trim_auth.rs
+++ b/examples/trim_auth.rs
@@ -1,7 +1,6 @@
-use color_eyre::Result;
-use git_url_parse::GitUrl;
+use git_url_parse::{GitUrl, GitUrlParseError};
-fn main() -> Result<()> {
+fn main() -> Result<(), GitUrlParseError> {
env_logger::init();
let test_vec = vec![
diff --git a/src/lib.rs b/src/lib.rs
index cad821d..08e4b93 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,14 +1,14 @@
-use color_eyre::eyre::{eyre, WrapErr};
-pub use color_eyre::Result;
-use regex::Regex;
use std::fmt;
use std::str::FromStr;
-use strum_macros::{Display, EnumString, EnumVariantNames};
-use tracing::debug;
+use strum::{Display, EnumString, VariantNames};
+use thiserror::Error;
use url::Url;
+#[cfg(feature = "tracing")]
+use tracing::debug;
+
/// Supported uri schemes for parsing
-#[derive(Debug, PartialEq, Eq, EnumString, EnumVariantNames, Clone, Display, Copy)]
+#[derive(Debug, PartialEq, Eq, EnumString, VariantNames, Clone, Display, Copy)]
#[strum(serialize_all = "kebab_case")]
pub enum Scheme {
/// Represents `file://` url scheme
@@ -136,7 +136,7 @@ impl Default for GitUrl {
}
impl FromStr for GitUrl {
- type Err = color_eyre::Report;
+ type Err = GitUrlParseError;
fn from_str(s: &str) -> Result {
GitUrl::parse(s)
@@ -154,14 +154,22 @@ impl GitUrl {
}
/// Returns a `Result` after normalizing and parsing `url` for metadata
- pub fn parse(url: &str) -> Result {
+ pub fn parse(url: &str) -> Result {
// Normalize the url so we can use Url crate to process ssh urls
- let normalized = normalize_url(url)
- .with_context(|| "Url normalization into url::Url failed".to_string())?;
+ let normalized = if let Ok(url) = normalize_url(url) {
+ url
+ } else {
+ return Err(GitUrlParseError::UrlNormalizeFailed);
+ };
// Some pre-processing for paths
- let scheme = Scheme::from_str(normalized.scheme())
- .with_context(|| format!("Scheme unsupported: {:?}", normalized.scheme()))?;
+ let scheme = if let Ok(scheme) = Scheme::from_str(normalized.scheme()) {
+ scheme
+ } else {
+ return Err(GitUrlParseError::UnsupportedScheme(
+ normalized.scheme().to_string(),
+ ));
+ };
// Normalized ssh urls can always have their first '/' removed
let urlpath = match &scheme {
@@ -177,6 +185,7 @@ impl GitUrl {
// Parse through path for name,owner,organization
// Support organizations for Azure Devops
+ #[cfg(feature = "tracing")]
debug!("The urlpath: {:?}", &urlpath);
// Most git services use the path for metadata in the same way, so we're going to separate
@@ -187,10 +196,14 @@ impl GitUrl {
//
// organizations are going to be supported on a per-host basis
let splitpath = &urlpath.rsplit_terminator('/').collect::>();
+
+ #[cfg(feature = "tracing")]
debug!("rsplit results for metadata: {:?}", splitpath);
let name = splitpath[0].trim_end_matches(".git").to_string();
+ // TODO: I think here is where we want to update the url pattern identification step.. I want to be able to have a hint that the user can pass
+
let (owner, organization, fullname) = match &scheme {
// We're not going to assume anything about metadata from a filepath
Scheme::File => (None::, None::, name.clone()),
@@ -201,12 +214,15 @@ impl GitUrl {
let hosts_w_organization_in_path = vec!["dev.azure.com", "ssh.dev.azure.com"];
//vec!["dev.azure.com", "ssh.dev.azure.com", "visualstudio.com"];
- let host_str = normalized
- .host_str()
- .ok_or(eyre!("Host from URL could not be represented as str"))?;
+ let host_str = if let Some(host) = normalized.host_str() {
+ host
+ } else {
+ return Err(GitUrlParseError::UnsupportedUrlHostFormat);
+ };
match hosts_w_organization_in_path.contains(&host_str) {
true => {
+ #[cfg(feature = "tracing")]
debug!("Found a git provider with an org");
// The path differs between git:// and https:// schemes
@@ -242,16 +258,18 @@ impl GitUrl {
fullname.join("/"),
)
}
- _ => return Err(eyre!("Scheme not supported for host")),
+
+ // TODO: I'm not sure if I want to support throwing this error long-term
+ _ => return Err(GitUrlParseError::UnexpectedScheme),
}
}
false => {
if !url.starts_with("ssh") && splitpath.len() < 2 {
- return Err(eyre!("git url is not of expected format"));
+ return Err(GitUrlParseError::UnexpectedFormat);
}
let position = match splitpath.len() {
- 0 => return Err(eyre!("git url is not of expected format")),
+ 0 => return Err(GitUrlParseError::UnexpectedFormat),
1 => 0,
_ => 1,
};
@@ -313,19 +331,21 @@ impl GitUrl {
/// Prepends `ssh://` to url
///
/// Supports absolute and relative paths
-fn normalize_ssh_url(url: &str) -> Result {
+fn normalize_ssh_url(url: &str) -> Result {
let u = url.split(':').collect::>();
match u.len() {
2 => {
+ #[cfg(feature = "tracing")]
debug!("Normalizing ssh url: {:?}", u);
normalize_url(&format!("ssh://{}/{}", u[0], u[1]))
}
3 => {
+ #[cfg(feature = "tracing")]
debug!("Normalizing ssh url with ports: {:?}", u);
normalize_url(&format!("ssh://{}:{}/{}", u[0], u[1], u[2]))
}
- _default => Err(eyre!("SSH normalization pattern not covered for: {:?}", u)),
+ _default => Err(GitUrlParseError::UnsupportedSshUrlFormat),
}
}
@@ -333,41 +353,47 @@ fn normalize_ssh_url(url: &str) -> Result {
///
/// Prepends `file://` to url
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
-fn normalize_file_path(filepath: &str) -> Result {
+fn normalize_file_path(filepath: &str) -> Result {
let fp = Url::from_file_path(filepath);
match fp {
Ok(path) => Ok(path),
- Err(_e) => Ok(normalize_url(&format!("file://{}", filepath))
- .with_context(|| "file:// normalization failed".to_string())?),
+ Err(_e) => {
+ if let Ok(file_url) = normalize_url(&format!("file://{}", filepath)) {
+ Ok(file_url)
+ } else {
+ return Err(GitUrlParseError::FileUrlNormalizeFailedSchemeAdded);
+ }
+ }
}
}
#[cfg(target_arch = "wasm32")]
-fn normalize_file_path(_filepath: &str) -> Result {
+fn normalize_file_path(_filepath: &str) -> Result {
unreachable!()
}
/// `normalize_url` takes in url as `&str` and takes an opinionated approach to identify
/// `ssh://` or `file://` urls that require more information to be added so that
/// they can be parsed more effectively by `url::Url::parse()`
-pub fn normalize_url(url: &str) -> Result {
+pub fn normalize_url(url: &str) -> Result {
+ #[cfg(feature = "tracing")]
debug!("Processing: {:?}", &url);
+ // TODO: Should this be extended to check for any whitespace?
// Error if there are null bytes within the url
// https://github.com/tjtelan/git-url-parse-rs/issues/16
if url.contains('\0') {
- return Err(eyre!("Found null bytes within input url before parsing"));
+ return Err(GitUrlParseError::FoundNullBytes);
}
// We're going to remove any trailing slash before running through Url::parse
let trim_url = url.trim_end_matches('/');
+ // TODO: Remove support for this form when I go to next major version.
+ // I forget what it supports, and it isn't obvious after searching for examples
// normalize short git url notation: git:host/path
- let url_to_parse = if Regex::new(r"^git:[^/]")
- .with_context(|| "Failed to build short git url regex for testing against url".to_string())?
- .is_match(trim_url)
- {
+ let url_to_parse = if trim_url.starts_with("git:") && !trim_url.starts_with("git://") {
trim_url.replace("git:", "git://")
} else {
trim_url.to_string()
@@ -381,37 +407,126 @@ pub fn normalize_url(url: &str) -> Result {
Ok(_p) => u,
Err(_e) => {
// Catch case when an ssh url is given w/o a user
+ #[cfg(feature = "tracing")]
debug!("Scheme parse fail. Assuming a userless ssh url");
- normalize_ssh_url(trim_url).with_context(|| {
- "No url scheme was found, then failed to normalize as ssh url.".to_string()
- })?
+ if let Ok(ssh_url) = normalize_ssh_url(trim_url) {
+ ssh_url
+ } else {
+ return Err(GitUrlParseError::SshUrlNormalizeFailedNoScheme);
+ }
}
}
}
- Err(url::ParseError::RelativeUrlWithoutBase) => {
- // If we're here, we're only looking for Scheme::Ssh or Scheme::File
+ // If we're here, we're only looking for Scheme::Ssh or Scheme::File
+ // TODO: Add test for this
+ Err(url::ParseError::RelativeUrlWithoutBase) => {
// Assuming we have found Scheme::Ssh if we can find an "@" before ":"
// Otherwise we have Scheme::File
- let re = Regex::new(r"^\S+(@)\S+(:).*$").with_context(|| {
- "Failed to build ssh git url regex for testing against url".to_string()
- })?;
+ //let re = Regex::new(r"^\S+(@)\S+(:).*$").with_context(|| {
+ // "Failed to build ssh git url regex for testing against url".to_string()
+ //})?;
- match re.is_match(trim_url) {
+ match is_ssh_url(trim_url) {
true => {
+ #[cfg(feature = "tracing")]
debug!("Scheme::SSH match for normalization");
- normalize_ssh_url(trim_url)
- .with_context(|| "Failed to normalize as ssh url".to_string())?
+ normalize_ssh_url(trim_url)?
}
false => {
+ #[cfg(feature = "tracing")]
debug!("Scheme::File match for normalization");
- normalize_file_path(trim_url)
- .with_context(|| "Failed to normalize as file url".to_string())?
+ normalize_file_path(trim_url)?
}
}
}
Err(err) => {
- return Err(eyre!("url parsing failed: {:?}", err));
+ return Err(GitUrlParseError::from(err));
}
})
}
+
+// Valid ssh `url` for cloning have a usernames,
+// but we don't require it classification or parsing purposes
+// However a path must be specified with a `:`
+fn is_ssh_url(url: &str) -> bool {
+ // if we do not have a path
+ if !url.contains(':') {
+ return false;
+ }
+
+ // if we have a username, expect it before the path (Are usernames with colons valid?)
+ if let (Some(at_pos), Some(colon_pos)) = (url.find('@'), url.find(':')) {
+ if colon_pos < at_pos {
+ return false;
+ }
+
+ // Make sure we provided a username, and not just `@`
+ let parts: Vec<&str> = url.split('@').collect();
+ if parts.len() != 2 && !parts[0].is_empty() {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ // it's an ssh url if we have a domain:path pattern
+ let parts: Vec<&str> = url.split(':').collect();
+
+ // FIXME: I am not sure how to validate a url with a port
+ //if parts.len() != 3 && !parts[0].is_empty() && !parts[1].is_empty() && !parts[2].is_empty() {
+ // return false;
+ //}
+
+ // This should also handle if a port is specified
+ // no port example: ssh://user@domain:path/to/repo.git
+ // port example: ssh://user@domain:port/path/to/repo.git
+ if parts.len() != 2 && !parts[0].is_empty() && !parts[1].is_empty() {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+#[derive(Error, Debug, PartialEq, Eq)]
+pub enum GitUrlParseError {
+ #[error("Error from Url crate")]
+ UrlParseError(#[from] url::ParseError),
+
+ #[error("Url normalization into url::Url failed")]
+ UrlNormalizeFailed,
+
+ #[error("No url scheme was found, then failed to normalize as ssh url.")]
+ SshUrlNormalizeFailedNoScheme,
+
+ #[error("No url scheme was found, then failed to normalize as ssh url after adding 'ssh://'")]
+ SshUrlNormalizeFailedSchemeAdded,
+
+ #[error("Failed to normalize as ssh url after adding 'ssh://'")]
+ SshUrlNormalizeFailedSchemeAddedWithPorts,
+
+ #[error("No url scheme was found, then failed to normalize as file url.")]
+ FileUrlNormalizeFailedNoScheme,
+
+ #[error(
+ "No url scheme was found, then failed to normalize as file url after adding 'file://'"
+ )]
+ FileUrlNormalizeFailedSchemeAdded,
+
+ #[error("Git Url not in expected format")]
+ UnexpectedFormat,
+
+ // FIXME: Keep an eye on this error for removal
+ #[error("Git Url for host using unexpected scheme")]
+ UnexpectedScheme,
+
+ #[error("Scheme unsupported: {0}")]
+ UnsupportedScheme(String),
+ #[error("Host from Url cannot be str or does not exist")]
+ UnsupportedUrlHostFormat,
+ #[error("Git Url not in expected format for SSH")]
+ UnsupportedSshUrlFormat,
+
+ #[error("Found null bytes within input url before parsing")]
+ FoundNullBytes,
+}
diff --git a/tests/normalize.rs b/tests/normalize.rs
index 5dbc010..1ffd37b 100644
--- a/tests/normalize.rs
+++ b/tests/normalize.rs
@@ -9,6 +9,8 @@ fn git() {
assert_eq!(normalized.as_str(), "git://host.tld/user/project-name.git");
}
+// I'm not even sure if this is a form that should be supported bc I can't find examples of it being used in the wild by another service
+//#[should_panic]
#[test]
fn git2() {
let test_url = "git:host.tld/user/project-name.git";
@@ -98,7 +100,7 @@ fn unix_file_no_scheme_rel_path() {
assert_eq!(normalized.as_str(), "file://../user/project-name.git");
}
-#[should_panic(expected = "assertion failed: `(left == right)")]
+#[should_panic]
#[test]
fn win_file_scheme_abs_path() {
let test_url = "file://c:\\user\\project-name.git";
@@ -108,7 +110,7 @@ fn win_file_scheme_abs_path() {
assert_eq!(normalized.as_str(), "file://c:\\user\\project-name.git");
}
-#[should_panic(expected = "assertion failed: `(left == right)")]
+#[should_panic]
#[test]
fn win_file_no_scheme_abs_path() {
let test_url = "c:\\user\\project-name.git";
@@ -163,3 +165,21 @@ fn null_in_input2() {
assert!(normalized.is_err());
}
+
+// From https://github.com/tjtelan/git-url-parse-rs/issues/51
+#[test]
+fn large_bad_input1() {
+ let test_url = std::iter::repeat("g@1::::").take(10000).collect::();
+ let normalized = normalize_url(&test_url);
+
+ assert!(normalized.is_err());
+}
+
+// From https://github.com/tjtelan/git-url-parse-rs/issues/51
+#[test]
+fn large_bad_input2() {
+ let test_url = std::iter::repeat(":").take(10000).collect::();
+ let normalized = normalize_url(&test_url);
+
+ assert!(normalized.is_err());
+}
diff --git a/tests/parse.rs b/tests/parse.rs
index 4bc55a4..deabb37 100644
--- a/tests/parse.rs
+++ b/tests/parse.rs
@@ -310,7 +310,7 @@ fn relative_windows_path() {
}
// Issue #7 - Absolute Windows paths will not parse at all
-#[should_panic(expected = "git url is not of expected format")]
+#[should_panic(expected = "URL parse failed: UnexpectedFormat")]
#[test]
fn absolute_windows_path() {
let test_url = "c:\\project-name.git";
@@ -341,7 +341,7 @@ fn ssh_user_path_not_acctname_reponame_format() {
assert!(e.is_err());
assert_eq!(
format!("{}", e.err().unwrap()),
- "git url is not of expected format"
+ "Git Url not in expected format"
);
}