@@ -97,6 +97,44 @@ impl GitRepository {
9797 format ! ( "git@{}:{}/{}.git" , self . host, self . org, self . name)
9898 }
9999
100+ /// Returns the URL for viewing a specific commit
101+ pub fn commit_url ( & self , hash : & str ) -> String {
102+ format ! (
103+ "https://{}/{}/{}/commit/{}" ,
104+ self . host, self . org, self . name, hash
105+ )
106+ }
107+
108+ /// Returns the URL for viewing a pull request
109+ pub fn pr_url ( & self , pr_number : & str ) -> String {
110+ format ! (
111+ "https://{}/{}/{}/pull/{}" ,
112+ self . host, self . org, self . name, pr_number
113+ )
114+ }
115+
116+ /// Try to find a PR number from a commit message
117+ pub fn pr_for_commit ( & self , hash : & str ) -> Option < String > {
118+ if let Some ( path) = & self . path {
119+ //
120+ if let Ok ( message) = git ( path, & [ "log" , "-1" , "--pretty=%B" , hash] ) {
121+ //
122+ if let Some ( captures) = message. find ( '#' ) {
123+ let after_hash = & message[ captures + 1 ..] ;
124+ let pr_number: String = after_hash
125+ . chars ( )
126+ . take_while ( char:: is_ascii_digit)
127+ . collect ( ) ;
128+
129+ if !pr_number. is_empty ( ) {
130+ return Some ( pr_number) ;
131+ }
132+ }
133+ }
134+ }
135+ None
136+ }
137+
100138 pub fn current_branch ( & self ) -> String {
101139 self . path
102140 . as_ref ( )
@@ -114,6 +152,43 @@ impl GitRepository {
114152 Err ( e) => Err ( e) ,
115153 }
116154 }
155+
156+ pub fn url ( current_dir : & str , paths : & [ String ] ) -> Result < String , RepositoryError > {
157+ let is_git = is_git_repo ( current_dir) ;
158+
159+ let join_paths = || match paths. join ( " " ) {
160+ path if path == "." => current_dir. to_string ( ) ,
161+ path => path,
162+ } ;
163+
164+ if !is_git {
165+ return Ok ( join_paths ( ) ) ;
166+ }
167+
168+ let r = Self :: from_path ( current_dir) ?;
169+
170+ if paths. is_empty ( ) {
171+ return Ok ( r. http_url ( ) ) ;
172+ }
173+
174+ if paths. len ( ) == 1 {
175+ let arg = & paths[ 0 ] ;
176+ let is_commit = is_valid_commit_hash ( arg) ;
177+
178+ if is_commit || is_pr_number ( arg) {
179+ return if is_commit {
180+ match r. pr_for_commit ( arg) {
181+ Some ( pr_number) => Ok ( r. pr_url ( & pr_number) ) ,
182+ None => Ok ( r. commit_url ( arg) ) ,
183+ }
184+ } else {
185+ Ok ( r. pr_url ( arg) )
186+ } ;
187+ }
188+ }
189+
190+ Ok ( join_paths ( ) )
191+ }
117192}
118193
119194impl fmt:: Debug for GitRepository {
@@ -146,6 +221,14 @@ pub fn is_git_repo(path: impl AsRef<Path>) -> bool {
146221 git ( & path, & [ "rev-parse" , "--git-dir" ] ) . is_ok ( )
147222}
148223
224+ pub fn is_valid_commit_hash ( hash : & str ) -> bool {
225+ hash. len ( ) >= 7 && hash. len ( ) <= 40 && hash. chars ( ) . all ( |c| c. is_ascii_hexdigit ( ) )
226+ }
227+
228+ pub fn is_pr_number ( s : & str ) -> bool {
229+ !s. is_empty ( ) && s. chars ( ) . all ( |c| c. is_ascii_digit ( ) )
230+ }
231+
149232#[ cfg( test) ]
150233mod tests {
151234 use super :: * ;
0 commit comments