mirror of
https://github.com/paulirish/git-open.git
synced 2026-09-10 07:26:15 -04:00
Merge pull request #109 from 4U6U57/master
Support domain expansion from sshconfig
This commit is contained in:
commit
d9b958087d
54
git-open
54
git-open
|
|
@ -56,12 +56,51 @@ if [[ -z "$giturl" ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
ssh_config=${ssh_config:-"$HOME/.ssh/config"}
|
||||
# Resolves an ssh alias defined in ssh_config to it's corresponding hostname
|
||||
# echos out result, should be used within subshell $( ssh_resolve $host )
|
||||
# echos out nothing if alias could not be resolved
|
||||
function ssh_resolve() {
|
||||
domain="$1"
|
||||
ssh_found=true
|
||||
# Filter to only ssh_config lines that start with "Host" or "HostName"
|
||||
resolved=$(while read -r ssh_line; do
|
||||
# Split each line by spaces, of the form:
|
||||
# Host alias [alias...]
|
||||
# Host regex
|
||||
# HostName resolved.domain.com
|
||||
read -r -a ssh_array <<<"${ssh_line}"
|
||||
ssh_optcode="${ssh_array[0]}"
|
||||
if [[ ${ssh_optcode^^} == HOST ]]; then
|
||||
# Host
|
||||
ssh_found=false
|
||||
# Iterate through aliases looking for a match
|
||||
for ssh_index in $(seq 1 $((${#ssh_array[@]} - 1))); do
|
||||
ssh_host=${ssh_array[$ssh_index]}
|
||||
# shellcheck disable=SC2053
|
||||
if [[ $domain == $ssh_host ]]; then
|
||||
# Found a match, next HostName entry will be returned while matched
|
||||
ssh_found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
elif $ssh_found && [[ ${ssh_optcode^^} == HOSTNAME ]]; then
|
||||
# HostName, but only if ssh_found is true (the last Host entry matched)
|
||||
# Replace all instances of %h with the Host alias
|
||||
echo "${ssh_array[1]//%h/$domain}"
|
||||
fi
|
||||
done < <(grep -iE "^\\s*Host(Name)?\\s+" "$ssh_config"))
|
||||
# Take only the last resolved hostname (multiple are overridden)
|
||||
tail -1 <<<"$resolved"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# [user@]hostalias:path/to/repo.git/ - handles host aliases defined in ssh_config(5)
|
||||
|
||||
# Determine whether this is a url (https, ssh, git+ssh...) or an scp-style path
|
||||
if [[ "$giturl" =~ ^[a-z\+]+://.* ]]; then
|
||||
|
|
@ -85,6 +124,14 @@ else
|
|||
# Split on first ':' to get server name and path
|
||||
domain=${uri%%:*}
|
||||
urlpath=${uri#*:}
|
||||
|
||||
# Resolve sshconfig aliases
|
||||
if [[ -e "$ssh_config" ]]; then
|
||||
domain_resolv=$(ssh_resolve "$domain")
|
||||
if [[ ! -z "$domain_resolv" ]]; then
|
||||
domain="$domain_resolv"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Trim "/" from beginning of URL; "/" and ".git" from end of URL
|
||||
|
|
@ -110,7 +157,7 @@ protocol=$(getConfig "protocol")
|
|||
branch=${2:-$(git symbolic-ref -q --short HEAD)}
|
||||
|
||||
# Split arguments on '/'
|
||||
IFS='/' pathargs=($urlpath)
|
||||
IFS='/' read -r -a pathargs <<<"$urlpath"
|
||||
|
||||
if (( is_issue )); then
|
||||
# For issues, take the numbers and preprend 'issues/'
|
||||
|
|
@ -133,6 +180,7 @@ elif [[ "${#pathargs[@]}" -ge 3 && ${pathargs[${#pathargs[@]} - 3]} == 'scm' ]];
|
|||
pathPref=("${pathargs[*]:0:${#pathargs[@]} - 3}")
|
||||
|
||||
# Replace the 'scm' element, with 'projects'. Keep the first argument, the string 'repos', and finally the rest of the arguments.
|
||||
# shellcheck disable=SC2206
|
||||
pathargs=(${pathPref[@]} 'projects' ${pathargs[${#pathargs[@]} - 2]} 'repos' "${pathargs[@]:${#pathargs[@]} - 1}")
|
||||
IFS='/' urlpath="${pathargs[*]}"
|
||||
providerBranchRef="/browse?at=$branch"
|
||||
|
|
@ -171,7 +219,9 @@ case $( uname -s ) in
|
|||
esac
|
||||
|
||||
# Allow printing the url if BROWSER=echo
|
||||
if [[ $BROWSER != "echo" ]]; then
|
||||
if [[ $BROWSER == "echo" ]]; then
|
||||
openopt=''
|
||||
else
|
||||
exec &>/dev/null
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,113 @@ setup() {
|
|||
assert_output "http://github.com/user/repo"
|
||||
}
|
||||
|
||||
##
|
||||
## SSH config
|
||||
##
|
||||
|
||||
@test "sshconfig: basic" {
|
||||
create_ssh_sandbox
|
||||
# Basic
|
||||
git remote set-url origin "basic:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output --partial "https://basic.com/user/repo"
|
||||
# With git user
|
||||
git remote set-url origin "git@nouser:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://no.user/user/repo"
|
||||
}
|
||||
|
||||
@test "sshconfig: no action on no match" {
|
||||
create_ssh_sandbox
|
||||
git remote set-url origin "git@nomatch:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://nomatch/user/repo"
|
||||
# No match due to improper casing
|
||||
}
|
||||
|
||||
@test "sshconfig: check case sensitivity" {
|
||||
create_ssh_sandbox
|
||||
# Host and HostName keywords should be case insensitive
|
||||
# But output URL will be case sensitive
|
||||
git remote set-url origin "malformed:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://MaL.FoRmEd/user/repo"
|
||||
# SSH aliases (hosts) are case sensitive, this should not match
|
||||
git remote set-url origin "git@MALFORMED:user/repo.git"
|
||||
run ../git-open
|
||||
refute_output "https://MaL.FoRmEd/user/repo"
|
||||
}
|
||||
|
||||
@test "sshconfig: multitarget host" {
|
||||
create_ssh_sandbox
|
||||
for i in $(seq 1 3); do
|
||||
git remote set-url origin "multi$i:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://multi.com/user/repo"
|
||||
done
|
||||
}
|
||||
|
||||
@test "sshconfig: host substitution in hostname" {
|
||||
create_ssh_sandbox
|
||||
for i in $(seq 1 3); do
|
||||
git remote set-url origin "sub$i:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://sub$i.multi.com/user/repo"
|
||||
done
|
||||
}
|
||||
|
||||
@test "sshconfig: host wildcard * matches zero or more chars" {
|
||||
create_ssh_sandbox
|
||||
# Normal *
|
||||
for str in "" "-prod" "-dev"; do
|
||||
git remote set-url origin "zero$str:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://zero.com/user/repo"
|
||||
done
|
||||
# * with substitution
|
||||
for str in "" "-prod" "-dev"; do
|
||||
git remote set-url origin "subzero$str:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://subzero$str.zero/user/repo"
|
||||
done
|
||||
}
|
||||
|
||||
@test "sshconfig: host wildcard ? matches exactly one char" {
|
||||
create_ssh_sandbox
|
||||
# Normal ?
|
||||
for i in $(seq 1 3); do
|
||||
git remote set-url origin "one$i:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://one.com/user/repo"
|
||||
done
|
||||
# Refute invalid match on ?
|
||||
for str in "" "-test"; do
|
||||
git remote set-url origin "one:user/repo.git"
|
||||
run ../git-open
|
||||
refute_output "https://one$str.com/user/repo"
|
||||
done
|
||||
|
||||
# ? with substitution
|
||||
for i in $(seq 1 3); do
|
||||
git remote set-url origin "subone$i:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://subone$i.one/user/repo"
|
||||
done
|
||||
# Refute invalid match on ? with substitution
|
||||
for str in "" "-test"; do
|
||||
git remote set-url origin "subone$str:user/repo.git"
|
||||
run ../git-open
|
||||
refute_output "https://subone$str.one/user/repo"
|
||||
done
|
||||
# Refute invalid match on ? with substitution
|
||||
}
|
||||
|
||||
@test "sshconfig: overriding host rules" {
|
||||
create_ssh_sandbox
|
||||
git remote set-url origin "zero-override:user/repo.git"
|
||||
run ../git-open
|
||||
assert_output "https://override.zero.com/user/repo"
|
||||
}
|
||||
|
||||
##
|
||||
## Bitbucket
|
||||
|
|
@ -393,6 +500,9 @@ setup() {
|
|||
teardown() {
|
||||
cd ..
|
||||
rm -rf "$foldername"
|
||||
rm -rf "$ssh_config"
|
||||
refute [ -e "$ssh_config" ]
|
||||
unset ssh_config
|
||||
}
|
||||
|
||||
# helper to create a test git sandbox that won't dirty the real repo
|
||||
|
|
@ -418,3 +528,65 @@ function create_git_sandbox() {
|
|||
git add readme.txt
|
||||
git commit -m "add file" -q
|
||||
}
|
||||
|
||||
# helper to create test SSH config file
|
||||
function create_ssh_sandbox() {
|
||||
export ssh_config=$(mktemp)
|
||||
refute [ -z "$ssh_config" ]
|
||||
|
||||
# Populate ssh config with test data
|
||||
echo "$ssh_testdata" >$ssh_config
|
||||
assert [ -e "$ssh_config" ]
|
||||
}
|
||||
|
||||
# Test SSH config data
|
||||
ssh_testdata="
|
||||
# Autogenerated test sshconfig for paulirish/git-open BATS tests
|
||||
# It is safe to delete this file, a new one will be generated each test
|
||||
|
||||
Host basic
|
||||
HostName basic.com
|
||||
User git
|
||||
|
||||
Host nomatch
|
||||
User git
|
||||
|
||||
Host nouser
|
||||
HostName no.user
|
||||
|
||||
host malformed
|
||||
hOsTnAmE MaL.FoRmEd
|
||||
User other
|
||||
|
||||
# Multiple targets
|
||||
Host multi1 multi2 multi3
|
||||
HostName multi.com
|
||||
User git
|
||||
|
||||
Host sub1 sub2 sub3
|
||||
HostName %h.multi.com
|
||||
User git
|
||||
|
||||
# Wildcard * matching (zero or more characters)
|
||||
Host zero*
|
||||
HostName zero.com
|
||||
User git
|
||||
|
||||
Host subzero*
|
||||
HostName %h.zero
|
||||
User git
|
||||
|
||||
# Wildcard ? matching (exactly one character)
|
||||
Host one?
|
||||
HostName one.com
|
||||
User git
|
||||
|
||||
Host subone?
|
||||
HostName %h.one
|
||||
User git
|
||||
|
||||
# Overrides rule zero*
|
||||
Host zero-override
|
||||
HostName override.zero.com
|
||||
User git
|
||||
"
|
||||
|
|
|
|||
Loading…
Reference in a new issue