Skip to content

Commit b37b0b2

Browse files
antoinecartonAntoine Carton
andauthored
Add merge request option (#47)
Co-authored-by: Antoine Carton <antoine@saagie.com>
1 parent 0665902 commit b37b0b2

2 files changed

Lines changed: 112 additions & 14 deletions

File tree

src/lib.rs

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ extern crate log;
99
mod git;
1010
pub mod options;
1111

12+
const BITBUCKET_HOSTNAME: &str = "bitbucket.org";
13+
const GITHUB_HOSTNAME: &str = "github.com";
14+
const GITLAB_HOSTNAME: &str = "gitlab.com";
15+
const GITEA_HOSTNAME: &str = "gitea.io";
16+
1217
#[derive(Debug, Eq, Error, PartialEq, Clone)]
1318
pub enum Issue {
1419
#[error("Command failed, please run command inside a git directory")]
@@ -23,6 +28,8 @@ pub enum Issue {
2328
BrowserNotAvailable(String),
2429
#[error("Unable to get remote parts, please open an issue as it might come from the code")]
2530
UnableToGetRemoteParts,
31+
#[error("Unknown provider")]
32+
UnknownProvider,
2633
}
2734

2835
pub struct Success;
@@ -37,6 +44,7 @@ impl Issue {
3744
Self::NotAbleToOpenSystemBrowser => 4,
3845
Self::BrowserNotAvailable(..) => 5,
3946
Self::UnableToGetRemoteParts => 6,
47+
Self::UnknownProvider => 7,
4048
}
4149
}
4250
}
@@ -57,10 +65,10 @@ impl Default for GitProvider {
5765
impl GitProvider {
5866
fn hostname(&self) -> String {
5967
match self {
60-
Self::GitHub => "github.com",
61-
Self::GitLab => "gitlab.com",
62-
Self::Bitbucket => "bitbucket.org",
63-
Self::Gitea => "gitea.io",
68+
Self::GitHub => GITHUB_HOSTNAME,
69+
Self::GitLab => GITLAB_HOSTNAME,
70+
Self::Bitbucket => BITBUCKET_HOSTNAME,
71+
Self::Gitea => GITEA_HOSTNAME,
6472
}
6573
.to_string()
6674
}
@@ -71,9 +79,14 @@ pub struct RemoteParts {
7179
repository: String,
7280
}
7381

82+
struct MergeRequestParts {
83+
path: String,
84+
tail: String,
85+
}
86+
7487
const DEFAULT_REMOTE_ORIGIN: &str = "origin";
7588

76-
pub fn get_remote_parts(url: &str) -> anyhow::Result<RemoteParts> {
89+
fn get_remote_parts(url: &str) -> anyhow::Result<RemoteParts> {
7790
let re: Regex = Regex::new(r"((\w+://)|(git@))(.+@)*(?P<domain>[\w\d.]+)(:[\d]+)?/*(:?)(?P<repository>[^.]*)(\.git)?(/)?$").unwrap();
7891

7992
let caps = re
@@ -91,6 +104,28 @@ pub fn get_remote_parts(url: &str) -> anyhow::Result<RemoteParts> {
91104
Ok(RemoteParts { domain, repository })
92105
}
93106

107+
fn get_merge_request_parts(domain: &str) -> anyhow::Result<MergeRequestParts, Issue> {
108+
match domain {
109+
GITHUB_HOSTNAME => Ok(MergeRequestParts {
110+
path: "pulls".to_string(),
111+
tail: "".to_string(),
112+
}),
113+
GITLAB_HOSTNAME => Ok(MergeRequestParts {
114+
path: "-/merge_requests".to_string(),
115+
tail: "".to_string(),
116+
}),
117+
BITBUCKET_HOSTNAME => Ok(MergeRequestParts {
118+
path: "pull-requests".to_string(),
119+
tail: "".to_string(),
120+
}),
121+
GITEA_HOSTNAME => Ok(MergeRequestParts {
122+
path: "pulls".to_string(),
123+
tail: "".to_string(),
124+
}),
125+
_ => Err(Issue::UnknownProvider)
126+
}
127+
}
128+
94129
pub fn run(opt: Opt) -> Result {
95130
// let logger = logger::Logger::new(opt.verbose);
96131
debug!("Verbose mode is active");
@@ -146,20 +181,23 @@ pub fn run(opt: Opt) -> Result {
146181
(path, reference)
147182
};
148183

149-
let url = format!(
150-
"https://{domain}/{repository}/{path}/{tail}",
151-
domain = domain,
152-
path = path,
153-
repository = repository,
154-
tail = tail
155-
);
184+
let (path, tail) = if opt.merge_request {
185+
debug!("Getting merge request parts for domain '{}'", domain);
186+
let MergeRequestParts { path, tail } = get_merge_request_parts(&domain).unwrap();
187+
(path.as_str().to_owned(), tail.as_str().to_owned())
188+
} else {
189+
(path.to_string(), tail.to_string())
190+
};
191+
192+
// Generate the requested url that has to be opened in the browser
193+
let url = generate_url(&domain, &repository, &path, &tail);
156194

157195
// If the option is available through the command line, open the given one
158196
match opt.browser {
159197
Some(option_browser) => {
160198
debug!("Browser '{}' given as option", option_browser);
161199

162-
if option_browser == "" {
200+
if option_browser == "".to_string() {
163201
println!("{}", url);
164202
}
165203

@@ -172,7 +210,7 @@ pub fn run(opt: Opt) -> Result {
172210
// Open the default web browser on the current system.
173211
match open::that(&url) {
174212
Ok(_) => {
175-
debug!("Default browser is now open");
213+
debug!("Default browser is now opened");
176214
Ok(Success)
177215
}
178216
Err(_) => Err(Issue::NotAbleToOpenSystemBrowser),
@@ -181,6 +219,16 @@ pub fn run(opt: Opt) -> Result {
181219
}
182220
}
183221

222+
fn generate_url(domain: &str, repository: &String, path: &String, tail: &String) -> String {
223+
format!(
224+
"https://{domain}/{repository}/{path}/{tail}",
225+
domain = domain,
226+
path = path,
227+
repository = repository,
228+
tail = tail
229+
)
230+
}
231+
184232
#[cfg(test)]
185233
mod tests {
186234
// Note this useful idiom: importing names from outer (for mod tests) scope.
@@ -240,4 +288,47 @@ mod tests {
240288
assert_eq!(domain, "host.xz");
241289
assert_eq!(repository, "path/to/repo");
242290
}
291+
292+
#[test]
293+
fn test_get_merge_request_parts_with_github() {
294+
let MergeRequestParts { path, tail } =
295+
get_merge_request_parts(GITHUB_HOSTNAME).unwrap();
296+
297+
assert_eq!(path, "pulls");
298+
assert_eq!(tail, "");
299+
}
300+
301+
#[test]
302+
fn test_get_merge_request_parts_with_gitlab() {
303+
let MergeRequestParts { path, tail } =
304+
get_merge_request_parts(GITLAB_HOSTNAME).unwrap();
305+
306+
assert_eq!(path, "-/merge_requests");
307+
assert_eq!(tail, "");
308+
}
309+
310+
#[test]
311+
fn test_get_merge_request_parts_with_bitbucket() {
312+
let MergeRequestParts { path, tail } =
313+
get_merge_request_parts(BITBUCKET_HOSTNAME).unwrap();
314+
315+
assert_eq!(path, "pull-requests");
316+
assert_eq!(tail, "");
317+
}
318+
319+
#[test]
320+
fn test_get_merge_request_parts_with_gitea() {
321+
let MergeRequestParts { path, tail } =
322+
get_merge_request_parts(GITEA_HOSTNAME).unwrap();
323+
324+
assert_eq!(path, "pulls");
325+
assert_eq!(tail, "");
326+
}
327+
328+
#[test]
329+
fn test_get_merge_request_parts_with_unknown_provider() {
330+
let result = get_merge_request_parts("host.xz");
331+
332+
assert_eq!(result.err(), Some(Issue::UnknownProvider));
333+
}
243334
}

src/options.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ pub struct Opt {
2222
#[structopt(short, long)]
2323
pub tag: Option<String>,
2424

25+
/// Set the merge request flag.
26+
///
27+
/// By setting the merge_request flag, you can override the default behavior that will
28+
/// open up the merge requests listing page.
29+
#[structopt(short = "-M", long = "--merge-request", conflicts_with_all = &["commit", "tag", "branch"])]
30+
pub merge_request: bool,
31+
2532
/// Set a commit
2633
///
2734
/// By setting a commit, you can override the default behavior that will

0 commit comments

Comments
 (0)