diff --git a/README.md b/README.md index dec489d..ad9aebe 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ git open [remote-name] [branch-name] git open --issue ``` -(`git open` works with these [hosted repo providers](#supported-remote-repositories), `git open --issue` currently only works with GitHub) +(`git open` works with these [hosted repo providers](#supported-remote-repositories), `git open --issue` currently only works with GitHub, Visual Studio Team Services and Team Foundation Server) ### Examples @@ -100,6 +100,8 @@ git-open can automatically guess the corresponding repository page for remotes - GitLab custom hosted (see below) - bitbucket.org - Atlassian Bitbucket Server (formerly _Atlassian Stash_) +- Visual Studio Team Services +- Team Foundation Server (on-premises) ### GitLab support diff --git a/git-open b/git-open index 9e3b304..e6f8463 100755 --- a/git-open +++ b/git-open @@ -62,17 +62,37 @@ fi # ftp[s]://host.xz[:port]/path/to/repo.git/ # [user@]host.xz:path/to/repo.git/ - scp-like but is an alternative to ssh. -# Trim "/" and ".git" from the end of the url -giturl=${giturl%/} giturl=${giturl%.git} +# Determine whether this is a url (https, ssh, git+ssh...) or an scp-style path +if [[ "$giturl" =~ ^[a-z\+]+://.* ]]; then + # Trim URL scheme and possible username + gitprotocol=${giturl%%://*} + uri=${giturl#*://} + uri=${uri#*@} -# Trim before last '@' and protocol (*://) from beginning -uri=${giturl##*@} uri=${uri##*://} + # Split on first '/ to get server name and path + domain=${uri%%/*} + urlpath=${uri#*/} -# If there isn't a protocol, we can assume it's using the scp syntax which uses ':' to seperate the path. -[[ $giturl =~ :// ]] && pathsep='/' || pathsep=':' + # Remove port number from non-http/https protocols (ie, ssh) + if [[ $gitprotocol != 'https' && $gitprotocol != 'http' ]]; then + domain=${domain%:*} + fi +else + # Trim possible username from SSH path + uri=${giturl##*@} -# Seperate the domain and the urlpath on the first {pathsep}. This also removes the gitport from the domain. -domain=${uri%%[:$pathsep]*} urlpath=${uri#*$pathsep} + # Split on first ':' to get server name and path + domain=${uri%%:*} + urlpath=${uri#*:} +fi + +# Trim "/" from beginning of URL; "/" and ".git" from end of URL +urlpath=${urlpath#/} urlpath=${urlpath%/} urlpath=${urlpath%.git} + +# If the URL is provided as "http", preserve that +if [[ $gitprotocol == 'http' ]]; then + protocol='http' +fi # Allow config options to replace the server or the protocol openurl="$protocol://$domain" @@ -93,30 +113,40 @@ IFS='/' pathargs=($urlpath) if (( is_issue )); then # For issues, take the numbers and preprend 'issues/' - providerBranchRef="issues/${branch//[^0-9]/}" + providerBranchRef="/issues/${branch//[^0-9]/}" else # Make # and % characters url friendly # github.com/paulirish/git-open/pull/24 branch=${branch//%/%25} branch=${branch//#/%23} - providerBranchRef="tree/$branch" + providerBranchRef="/tree/$branch" fi if [[ "$domain" == 'bitbucket.org' ]]; then # Bitbucket, see https://github.com/paulirish/git-open/issues/80 for why ?at is needed. - providerBranchRef="src?at=$branch" + providerBranchRef="/src?at=$branch" elif [[ ${pathargs[0]} == 'scm' ]]; then # Bitbucket server, which starts with 'scm' # Replace the first element, 'scm', with 'projects'. Keep the first argument, the string 'repos', and finally the rest of the arguments. pathargs=('projects' ${pathargs[1]} 'repos' "${pathargs[@]:2}") IFS='/' urlpath="${pathargs[*]}" - providerBranchRef="browse?at=$branch" + providerBranchRef="/browse?at=$branch" +elif [[ "${#pathargs[@]}" -ge '2' && ${pathargs[${#pathargs[@]} - 2]} == '_git' ]]; then + # Visual Studio Team Services and Team Foundation Server always have /_git/ as the second to last segment in the url path + if (( is_issue )); then + # Switch to workitems, provide work item id if specified + urlpath="${urlpath%%/_git/*}/_workitems" + providerBranchRef="?id=${branch//[^0-9]/}" + else + # Keep project and repository name, append branch selector. + providerBranchRef="?version=GB$branch" + fi fi openurl="$protocol://$domain/$urlpath" # simplify URL for master if [[ $branch != "master" ]]; then - openurl="$openurl/$providerBranchRef" + openurl="$openurl$providerBranchRef" fi # get current open browser command diff --git a/test/git-open.bats b/test/git-open.bats index 3401349..c3abd6c 100755 --- a/test/git-open.bats +++ b/test/git-open.bats @@ -144,6 +144,24 @@ setup() { assert_output "https://github.com/paulirish/git-open" } +@test "basic: https url can contain port" { + git remote set-url origin "https://github.com:99/user/repo.git" + run ../git-open + assert_output "https://github.com:99/user/repo" +} + +@test "basic: ssh url has port removed from http url" { + git remote set-url origin "ssh://github.com:22/user/repo.git" + run ../git-open + assert_output "https://github.com/user/repo" +} + +@test "basic: http url scheme is preserved" { + git remote set-url origin "http://github.com/user/repo.git" + run ../git-open + assert_output "http://github.com/user/repo" +} + ## ## Bitbucket @@ -299,10 +317,53 @@ setup() { git remote set-url origin "https://git.example.com:7000/XXX/YYY.git" run ../git-open - assert_output "https://git.example.com/XXX/YYY" - refute_output --partial ":7000" + assert_output "https://git.example.com:7000/XXX/YYY" } +## +## Visual Studio Team Services +## + +@test "vsts: https url" { + git remote set-url origin "https://gitopen.visualstudio.com/Project/_git/Repository" + run ../git-open + assert_output --partial "https://gitopen.visualstudio.com/Project/_git/Repository" +} + +@test "vsts: ssh url" { + git remote add vsts_ssh "ssh://gitopen@gitopen.visualstudio.com:22/Project/_git/Repository" + run ../git-open "vsts_ssh" + assert_output "https://gitopen.visualstudio.com/Project/_git/Repository" +} + +@test "vsts: on-premises tfs http url" { + git remote set-url origin "http://tfs.example.com:8080/Project/_git/Repository" + run ../git-open + assert_output --partial "http://tfs.example.com:8080/Project/_git/Repository" +} + +@test "vsts: branch" { + git remote set-url origin "ssh://gitopen@gitopen.visualstudio.com:22/_git/Repository" + git checkout -B "mybranch" + run ../git-open + assert_output "https://gitopen.visualstudio.com/_git/Repository?version=GBmybranch" +} + +@test "vsts: on-premises tfs branch" { + git remote set-url origin "http://tfs.example.com:8080/Project/Folder/_git/Repository" + git checkout -B "mybranch" + run ../git-open + assert_output "http://tfs.example.com:8080/Project/Folder/_git/Repository?version=GBmybranch" +} + +@test "vsts: issue" { + git remote set-url origin "http://tfs.example.com:8080/Project/Folder/_git/Repository" + git checkout -B "bugfix-36" + run ../git-open "--issue" + assert_output "http://tfs.example.com:8080/Project/Folder/_workitems?id=36" +} + + teardown() { cd .. rm -rf "$foldername"