@@ -9,6 +9,11 @@ extern crate log;
99mod git;
1010pub 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 ) ]
1318pub 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
2835pub 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 {
5765impl 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+
7487const 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+
94129pub 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) ]
185233mod 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}
0 commit comments