mirror of
https://github.com/chenasraf/git-open.git
synced 2026-05-18 01:38:59 +00:00
409 lines
10 KiB
Bash
Executable File
409 lines
10 KiB
Bash
Executable File
#!/usr/bin/env zsh
|
|
|
|
if [[ -z "$__UTILS_PATH" ]]; then
|
|
__UTILS_PATH="${0:A:h}/utils.zsh"
|
|
fi
|
|
. "$__UTILS_PATH"
|
|
silent=""
|
|
|
|
uriencode() {
|
|
len="${#1}"
|
|
for ((n = 0; n < len; n++)); do
|
|
c="${1:$n:1}"
|
|
case $c in
|
|
[a-zA-Z0-9.~_-]) printf "$c" ;;
|
|
*) printf '%%%02X' "'$c" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
trim() {
|
|
echo "$1" | sed -E 's/^[ \t]+|[ \t]+$//g'
|
|
}
|
|
|
|
git_get_remote() {
|
|
remote=$(git remote -v | grep "(push)" | awk '{print $1, $2}')
|
|
# Prefer "origin" remote if available, otherwise use the first one
|
|
selected=$(echo "$remote" | grep "^origin " | head -1 | awk '{print $2}')
|
|
if [[ -z "$selected" ]]; then
|
|
selected=$(echo "$remote" | head -1 | awk '{print $2}')
|
|
fi
|
|
echo $selected
|
|
}
|
|
|
|
git_get_repo_path() {
|
|
remote=$1
|
|
repo_path=''
|
|
|
|
if [[ $remote =~ ^git@ ]]; then
|
|
repo_path=$(echo "$remote" | sed -E 's|^git@[^:]+:([^:]+)\.git$|\1|')
|
|
repo_path=$(echo "$repo_path" | sed -E 's|^git@[^:]+:([^:]+)$|\1|')
|
|
elif [[ $remote =~ ^https?:// ]]; then
|
|
repo_path=$(echo "$remote" | sed -E 's|^https?://[^/]+/([^\.]+)\.git$|\1|')
|
|
repo_path=$(echo "$repo_path" | sed -E 's|^https?://[^/]+/([^\.]+)$|\1|')
|
|
fi
|
|
echo $repo_path
|
|
}
|
|
|
|
git_get_remote_type() {
|
|
remote=$1
|
|
repo_path=$(git_get_repo_path $remote)
|
|
remote_type='github'
|
|
case $remote in
|
|
*github.com*) remote_type='github' ;;
|
|
*gitlab.com*) remote_type='gitlab' ;;
|
|
*bitbucket.org*) remote_type='bitbucket' ;;
|
|
*) return 1 ;;
|
|
esac
|
|
|
|
echo $remote_type
|
|
return 0
|
|
}
|
|
|
|
git_open_project() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path" ;;
|
|
*)
|
|
echo "Unknown remote type: $remote_type"
|
|
return 2
|
|
;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_branch() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
branch=$([[ -n "$2" ]] && echo "$2" || git branch --show-current)
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/tree/$branch" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/-/tree/$branch" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/branch/$branch" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_file() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
prefix=${GIT_PREFIX:-$(git rev-parse --show-prefix 2>/dev/null)}
|
|
file=$([[ -n "$2" ]] && echo "${prefix}$2" || echo "")
|
|
branch=$([[ -n "$3" ]] && echo "$3" || git branch --show-current)
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/blob/$branch/$file" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/-/blob/$branch/$file" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/src/$file" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_commit() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
commit=$([[ -n "$2" ]] && echo "$2" || git rev-parse HEAD)
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/commit/$commit" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/-/commit/$commit" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/commit/$commit" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_pr_list() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/pulls?q=is%3Apr+is%3Aopen" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/merge_requests?scope=all&state=opened" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/pull-requests?state=OPEN" ;;
|
|
*)
|
|
echo "Unknown remote type: $remote_type"
|
|
return 2
|
|
;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_new_pr() {
|
|
if [[ "$1" == "--force" || "$1" == "-f" ]]; then
|
|
shift
|
|
existing=""
|
|
else
|
|
existing="$(git_find_pr $@)"
|
|
fi
|
|
|
|
if [[ -n "$existing" ]]; then
|
|
open_url "$silent" $existing
|
|
return 0
|
|
fi
|
|
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
branch=$([[ -n "$1" ]] && echo "$1" || git branch --show-current)
|
|
default_branch=$([[ -n "$2" ]] && echo "$2" || echo $(git remote show $remote | grep "HEAD branch" | awk '{print $3}'))
|
|
if [[ -z $default_branch ]]; then
|
|
default_branch="master"
|
|
fi
|
|
|
|
branch="$(uriencode "$(trim "$branch")")"
|
|
default_branch="$(uriencode "$(trim "$default_branch")")"
|
|
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/compare/$default_branch...$branch" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/-/merge_requests/new?merge_request%5Bsource_branch%5D=$branch&merge_request%5Btarget_branch%5D=$default_branch" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/pull-requests/new?source=$branch&t=1" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_find_pr() {
|
|
remote=$(git_get_remote)
|
|
if [[ -z "$remote" ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z "$remote_type" ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
branch="$([[ -n "$1" ]] && echo "$1" || git branch --show-current)"
|
|
commit="$(git rev-parse $branch)"
|
|
|
|
case "$remote_type" in
|
|
github)
|
|
prrefs="pull/*/head"
|
|
prfilt="pull"
|
|
;;
|
|
gitlab)
|
|
prrefs="merge-requests/*/head"
|
|
prfilt="merge-requests"
|
|
;;
|
|
bitbucket)
|
|
prrefs="pull-requests/*/head"
|
|
prfilt="pull-requests"
|
|
;;
|
|
esac
|
|
|
|
prid="$(git ls-remote origin $prrefs | grep "refs/$prfilt" | grep $commit | awk '{print $2}' | cut -d'/' -f3)"
|
|
|
|
if [[ -z $prid ]]; then
|
|
return 1
|
|
fi
|
|
|
|
case "$remote_type" in
|
|
github) echo "https://github.com/$repo_path/pull/$prid" ;;
|
|
gitlab) echo "https://gitlab.com/$repo_path/-/merge_requests/$prid" ;;
|
|
bitbucket) echo "https://bitbucket.org/$repo_path/pull-requests/$prid" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open_pipelines() {
|
|
branch=$1
|
|
if [[ -z $branch ]]; then
|
|
branch=$(git branch --show-current)
|
|
fi
|
|
|
|
remote=$(git_get_remote)
|
|
if [[ -z $remote ]]; then
|
|
echo "No remote found"
|
|
return 1
|
|
fi
|
|
|
|
remote_type=$(git_get_remote_type $remote)
|
|
if [[ -z $remote_type ]]; then
|
|
echo "Unknown remote type for $remote"
|
|
return 1
|
|
fi
|
|
|
|
repo_path=$(git_get_repo_path $remote)
|
|
case "$remote_type" in
|
|
github) open_url "$silent" "https://github.com/$repo_path/actions" ;;
|
|
gitlab) open_url "$silent" "https://gitlab.com/$repo_path/pipelines?scope=all" ;;
|
|
bitbucket) open_url "$silent" "https://bitbucket.org/$repo_path/addon/pipelines/home" ;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
git_open() {
|
|
if [[ -z $1 ]]; then
|
|
echo "Usage: git open [-s] <command>"
|
|
echo
|
|
echo "Opens various Git project related URLs in your browser."
|
|
echo
|
|
echo "Commands:"
|
|
echo " project|repo[sitory]|open|. Open the project"
|
|
echo " branch Open the project at given (or current) branch"
|
|
echo " commit Open the project at given (or current) commit"
|
|
echo " file Open the project at given file"
|
|
echo " file <branch|commit|ref> Open the project at given file for given ref"
|
|
echo " prs|mrs Open the PR list"
|
|
echo " pr|mr Create a new PR or open existing one"
|
|
echo " pr|mr <source branch> Create a new PR or open existing one for given branch"
|
|
echo " pr|mr <source> <target> Create a new PR or open existing one for given source and target"
|
|
echo " actions|pipelines|ci Open the CI/CD pipelines"
|
|
echo
|
|
echo "Flags:"
|
|
echo " -s, --silent Silent mode (no output)"
|
|
return 1
|
|
fi
|
|
|
|
case $1 in
|
|
project | repo | repository | \.) git_open_project ;;
|
|
branch) git_open_branch $@ ;;
|
|
file) git_open_file $@ ;;
|
|
commit) git_open_commit $@ ;;
|
|
prs | mrs)
|
|
shift
|
|
git_open_pr_list
|
|
;;
|
|
pr | mr)
|
|
shift
|
|
git_open_new_pr $@
|
|
;;
|
|
actions | pipelines | ci)
|
|
shift
|
|
git_open_pipelines
|
|
;;
|
|
--version | -V)
|
|
u="$(tput smul)"
|
|
r="$(tput sgr0)"
|
|
curyear=$(date +'%Y')
|
|
echo "git-open v$(cat "${0:A:h}/version.txt")"
|
|
echo "${u}https://github.com/chenasraf/git-open${r}"
|
|
echo "Copyright \xC2\xA9 2024-$curyear Chen Asraf"
|
|
;;
|
|
_debug)
|
|
inf="Getting info"
|
|
y=$(tput setaf 3)
|
|
g=$(tput setaf 2)
|
|
r=$(tput sgr0)
|
|
|
|
echo -n "$r- ${y}$inf\r"
|
|
remote=$(git_get_remote)
|
|
echo -n "$r\\ ${y}$inf.\r"
|
|
info=$(git remote show $remote)
|
|
echo -n "$r| ${y}$inf..\r"
|
|
branch=$(git branch --show-current)
|
|
echo -n "$r/ ${y}$inf...\r"
|
|
commit=$(git rev-parse HEAD)
|
|
echo "${g}Done\e[0K$r\n"
|
|
echo "Remote: $remote"
|
|
echo "Repo Path: $(git_get_repo_path $remote)"
|
|
echo "Remote Type: $(git_get_remote_type $remote)"
|
|
echo "Current Branch: $branch"
|
|
echo "Default Branch: $(echo $info | grep "HEAD branch" | awk '{print $3}')"
|
|
echo "Current Ref: $commit"
|
|
;;
|
|
*)
|
|
echo "Unknown command: $1"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
while true; do
|
|
case "$1" in
|
|
open) shift ;;
|
|
-s | --silent)
|
|
shift
|
|
silent="-s"
|
|
;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
git_open $@
|
|
|
|
if [[ -z "$__UNLOAD_PATH" ]]; then
|
|
__UNLOAD_PATH="${0:A:h}/unload.zsh"
|
|
fi
|
|
|
|
. "$__UNLOAD_PATH"
|