Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active October 15, 2015 19:38
Show Gist options
  • Save nilium/5de1dff359c142bb72a5 to your computer and use it in GitHub Desktop.
Save nilium/5de1dff359c142bb72a5 to your computer and use it in GitHub Desktop.
GitLab CLI tool (early days) — making it just because all the other CLI tools are apparently not intended for humans
#!/usr/bin/env bash
export API="${API:-$(git config gitlab.endpoint)}"
export TOKEN="${TOKEN:-$(git config gitlab.token)}"
export API="${API%*/}"
export self="${BASH_SOURCE[0]}"
if [[ -z "$API" ]] || [[ -z "$TOKEN" ]] ; then
cat <<-EOF 1>&2
API and TOKEN environment variables must be set, or you need to
set gitlab.endpoint and gitlab.token in your Git config.
API is the GitLab API endpoint and uses the Git config key
gitlab.endpoint by default. TOKEN is your personal GitLab API token,
and uses the Git config key gitlab.token by default.
git config --global gitlab.endpoint https://example.com/api/v3
git config --global gitlab.token YOUR-PRIVATE-TOKEN
Your private token can be found in your user profile under the
account section (path /profile/account).
EOF
exit 1
fi
if ! which nab 1>/dev/null 2>/dev/null ; then
cat <<-EOF 1>&2
You must have nab v1.1.1 or newer in your PATH to use git-lab.
You can download nab for your OS at:
https://github.com/nilium/nab/releases
EOF
exit 1
fi
stripnl () {
xargs echo -n
}
send () {
method="$1"
path="$2"
shift
shift
curl -s --request "${method}" \
--header "PRIVATE-TOKEN: ${TOKEN}" \
-L "${API}${path}" \
"$@"
}
search_namespaces () {
send GET /namespaces -G -d search="$1" | nab '{{ range . }}{{ .id }}{{ nl }}{{ end }}'
}
first_namespace () {
search_namespaces "$1" | head -n1
}
new_project () {
inargs=1
unset desc
showresp=0
openafter=0
allowinit=0
unset remotename
while [[ $# != 0 ]] ; do
if [[ $1 != '-'* ]] ; then break ; fi
if [[ $1 == '--' ]] ; then
shift
break
fi
arg="$1"
shift
case "$arg" in
-desc)
desc="description=$1"
shift
;;
-open)
openafter=1
;;
-clone)
cloneafter=1
;;
-clone=*)
cloneafter=1
clonepath="${arg%/*}"
shift
;;
-origin)
remotename="origin"
;;
-remote)
if [[ "$1" != '--' ]] ; then
remotename="$1"
shift
else
remotename="origin"
fi
;;
-remote=*)
remotename="${1%-remote=*}"
;;
-init)
allowinit=1
;;
-resp)
showresp=1
;;
*)
echo "unknown argument '$arg'" 1>&2
;;
esac
done
if [[ $# == 0 ]] ; then
echo "No project name given" 2>&1
exit 1
fi
namespace=''
name="$1"
case $name in
*/*)
namespace="$(first_namespace "${name%/*}" | stripnl)"
project="${name#*/}"
;;
*)
namespace="$("$self" user id | stripnl)"
project="$name"
;;
esac
data="$(send POST /projects -d name="$project" -d namespace_id="$namespace" ${desc:+-d} "$desc")"
msg="$(echo "$data" | nab "{{ if .message }}{{ .message }}{{ end }}}")"
if [[ -z $msg ]] ; then
echo "$data" | nab '{{ . | prettyjson }}' 1>&2
exit 1
fi
if [[ $openafter == 1 ]] ; then
open "$(echo "$data" | nab '{{ .web_url }}')"
fi
if [[ $cloneafter == 1 ]] ; then
if [[ -n $clonepath ]] ; then
git clone "$(echo "$data" | nab '{{ .ssh_url_to_repo }}')" "$clonepath"
else
git clone "$(echo "$data" | nab '{{ .ssh_url_to_repo }}')"
fi
remotename=''
fi
if [[ -n "$remotename" ]] ; then
echo "Trying to add remote named $remotename" 1>&2
ok=0
if git rev-parse --show-toplevel 2>/dev/null ; then
ok=1
elif [[ $allowinit == 1 ]] ; then
if git init ; then
ok=1
fi
fi
if [[ $ok == 1 ]] ; then
git remote add "$remotename" "$(echo "$data" | nab '{{ .ssh_url_to_repo }}')"
else
echo "Not in a git repo and -init not provided, cannot add remote $remotename" 1>&2
fi
fi
if [[ $showresp == 1 ]] ; then
echo "$data" | nab '{{ . | prettyjson }}'
fi
}
project_cmd () {
cmd="$1"
shift
case "$cmd" in
new|create)
new_project "$@"
;;
esac
}
show_help () {
cat <<-EOF
git-lab CMD [OPTIONS]
Commands:
user
Prints your user ID or any number of fields from your user profile.
ns
Looks up a namespace ID by the search term given.
project new [NAMESPACE/]PROJECT
Creates a new project in GitLab. If you specify a namespace, the
first namespace found by searching for 'NAMESPACE' is used. Otherwise,
the project is created for your user.
OPTIONS
-init
Allow a git repository to be initialized in the working directory
if you are not already in a git repository. This only applies if
adding a remote for the new project.
-origin
-remote=NAME
-remote NAME
The remote name to use if adding it to a repo. -origin is a shortcut
for -remote=origin.
-resp
Pretty-print the JSON response.
-open
Open the new project page using your default browser. Requires
OS X-compatible 'open' command right now.
-clone
-clone=PATH
Clone the project after creating it. If a PATH is provided, the
project is cloned into that path.
-remote and -init cannot be specified with this option.
EOF
}
if [[ $# == 0 ]] ; then
show_help
exit 1
fi
cmd="$1"
shift
case "$cmd" in
help)
show_help
exit 0
;;
curl)
send "$@"
;;
user)
if [[ $# == 0 ]] ; then
send GET /user | nab '{{ range $k, $v := . }}{{ $k }}: {{ $v }}{{ nl }}{{ end }}'
else
send GET /user | nab "$(for arg in "$@" ; do echo "{{ .$arg }}" ; done){{ nl }}"
fi
;;
ns)
search_namespaces "$@"
;;
project)
project_cmd "$@"
;;
*)
echo "Unrecognized command '$cmd'" 1>&2
echo '' 1>&2
show_help
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment