mirror of
https://github.com/paulirish/git-open.git
synced 2026-09-10 07:26:15 -04:00
* Parse remotes as URLs or SCP-style paths
Instead of trying to strip on ':' and '/' to simplify a URL, actually
switch based on whether the remote path is a URL ("scheme://host:port/path")
or an SCP-style path (user@host:path) and parse them separately.
This allows us to handle custom ports in HTTP and HTTPS, but ignore
custom ports in an SSH url and HTTP remotes, instead of always upgrading
them to HTTPS.
* Introduce tests for Visual Studio Team Services
Add tests for Visual Studio Team Services (VSTS) and Team Foundation
Server (TFS). VSTS suggests remote paths in two formats: HTTPS URLs
or SSH URLs (including port number). TFS is an on-premises product
which - when running as an HTTP endpoint - defaults to port 8080.
* Branch selection in Visual Studio Team Services
VSTS and TFS URLs end in '/_git/RepositoryName` (with 0 or more leading
folders of hierarchy in front of that.) Detect these from the `_git` in
the penultimate folder of the path. Append branch information to VSTS
and TFS URLs.
Since VSTS and TFS use a query string to select a branch, instead of
including it in the server path, the `providerBranchRef` for other
services was changed to include the leading `/`, and now the `openurl`
and `providerBranchRef` are simply concatenated, to avoid an incorrect
trailing `/` for the VSTS and TFS branch URLs.
* Issues for Visual Studio Team Services
Provide issue support for VSTS and TFS, modifying the URL from the
`_git` endpoint to the `_workitems` endpoint and appending the `id`
query string.
* README: add VSTS and TFS support
174 lines
5 KiB
Bash
Executable file
174 lines
5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# Use git-sh-setup, similar to git-rebase
|
|
# https://www.kernel.org/pub/software/scm/git/docs/git-sh-setup.html
|
|
# https://github.com/git/git/blob/master/git-rebase.sh
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_STUCKLONG=t
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_KEEPDASHDASH=
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_SPEC="\
|
|
git open [options]
|
|
git open [remote] [branch]
|
|
--
|
|
Opens the GitHub page for a repo/branch in your browser.
|
|
https://github.com/paulirish/git-open/
|
|
|
|
Available options are
|
|
i,issue! open issues page
|
|
"
|
|
|
|
# https://github.com/koalaman/shellcheck/wiki/SC1090
|
|
# shellcheck source=/dev/null
|
|
. "$(git --exec-path)/git-sh-setup"
|
|
|
|
# Defaults
|
|
is_issue=0
|
|
protocol="https"
|
|
|
|
while test $# != 0; do
|
|
case "$1" in
|
|
--issue) is_issue=1;;
|
|
--) shift; break ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# are we in a git repo?
|
|
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
echo "Not a git repository." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# choose remote. priority to: provided argument, detected tracked remote, 'origin'
|
|
branch_name=$(git name-rev --name-only HEAD 2>/dev/null)
|
|
tracked_remote=$(git config "branch.$branch_name.remote")
|
|
remote=${1:-$tracked_remote}
|
|
remote=${remote:-"origin"}
|
|
|
|
# @TODO ls-remote will also expand "insteadOf" items `giturl=$(git ls-remote --get-url $remote)``
|
|
giturl=$(git config --get "remote.${remote}.url")
|
|
|
|
if [[ -z "$giturl" ]]; then
|
|
echo "Git remote is not set for $remote" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# From git-fetch(5), native protocols:
|
|
# ssh://[user@]host.xz[:port]/path/to/repo.git/
|
|
# git://host.xz[:port]/path/to/repo.git/
|
|
# http[s]://host.xz[:port]/path/to/repo.git/
|
|
# ftp[s]://host.xz[:port]/path/to/repo.git/
|
|
# [user@]host.xz:path/to/repo.git/ - scp-like but is an alternative to ssh.
|
|
|
|
# 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#*@}
|
|
|
|
# Split on first '/ to get server name and path
|
|
domain=${uri%%/*}
|
|
urlpath=${uri#*/}
|
|
|
|
# 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##*@}
|
|
|
|
# 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"
|
|
|
|
function getConfig() {
|
|
config=$(git config --get-urlmatch "open.$1" "$openurl")
|
|
echo "${config:-${!1}}"
|
|
}
|
|
|
|
domain=$(getConfig "domain")
|
|
protocol=$(getConfig "protocol")
|
|
|
|
# Get current branch
|
|
branch=${2:-$(git symbolic-ref -q --short HEAD)}
|
|
|
|
# Split arguments on '/'
|
|
IFS='/' pathargs=($urlpath)
|
|
|
|
if (( is_issue )); then
|
|
# For issues, take the numbers and preprend 'issues/'
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
fi
|
|
|
|
# get current open browser command
|
|
case $( uname -s ) in
|
|
Darwin) open='open';;
|
|
MINGW*) open='start';;
|
|
MSYS*) open='start';;
|
|
CYGWIN*) open='cygstart';;
|
|
*) # Try to detect WSL (Windows Subsystem for Linux)
|
|
if uname -r | grep -q Microsoft; then
|
|
open='powershell.exe'
|
|
openopt='Start'
|
|
else
|
|
open='xdg-open'
|
|
fi;;
|
|
esac
|
|
|
|
# Allow printing the url if BROWSER=echo
|
|
if [[ $BROWSER != "echo" ]]; then
|
|
exec &>/dev/null
|
|
fi
|
|
|
|
# open it in a browser
|
|
${BROWSER:-$open} $openopt "$openurl"
|