Skip to content

Instantly share code, notes, and snippets.

@dhruvasagar
Last active February 2, 2020 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhruvasagar/6db76639d8874eb9ffd091021bedba8e to your computer and use it in GitHub Desktop.
Save dhruvasagar/6db76639d8874eb9ffd091021bedba8e to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# GistID: 6db76639d8874eb9ffd091021bedba8e
set -e
info () {
tput setaf 6; echo "$1"; tput sgr0
}
error () {
tput setaf 1; (>&2 echo "$1"); tput sgr0
}
success () {
tput setaf 2; echo "$1"; tput sgr0
}
if [ ! -x "$(command -v jq)" ] || [ ! -x "$(command -v hub)" ]; then
error 'Please install following dependencies: '
error '* jq <https://stedolan.github.io/jq/>'
error '* hub <https://github.com/github/hub>'
exit 1
fi
get_prno () {
echo "${1##*/}"
}
get_repo () {
local url="$1"
# remove everything till github.com
local repo=${url##*github.com/}
# remove everything at back end from /pull
local repo=${repo%%/pull*}
echo "$repo"
}
usage () {
cat <<EOM
$0 v0.0.1
Dhruva Sagar <dhruva.sagar@gmail.com>
Review creates a simple workflow for adding reviews for github PRs from cli
REQUIREMENTS:
jq <https://stedolan.github.io/jq/>
hub <https://github.com/github/hub>
USAGE:
$0 [COMMAND] [ARGS]
COMMANDS:
create <PR>
Create a new review for given PR
eg.) $0 create https://github.com/dhruvasagar/vim-table-mode/pull/1
submit <PR>
Submit a pending review for given PR
Prompts for :
* Review ID
* Comment
* Review Action (APPROVE | REQUEST_CHANGES | COMMENT)
delete <PR>
Delete a pending review for given PR
Prompts for :
* Review ID
invoke [ARGS]
This allows you to invoke any function within this script individually.
Useful for debugging.
eg.)
EXAMPLES:
$ $0 create https://github.com/dhruvasagar/vim-table-mode/pull/1
Opening PR 1
# add comments by reviewing diff within vim then close vim
Submitting review...
Review response saved at /tmp/file
$ $0 submit https://github.com/dhruvasagar/vim-table-mode/pull/1
Enter review ID:
123
Enter Review comment:
Test comment
Enter Review Action (APPROVE | REQUEST_CHANGES | COMMENT):
APPROVE
Submiting Review ID: 123
API Response
$ $0 delete https://github.com/dhruvasagar/vim-table-mode/pull/1
Enter review ID:
123
Deleting Review ID: 123
API Response
$ $0 invoke get_prno https://github.com/dhruvasagar/vim-table-mode/pull/1
Invoking comment get_prno with args https://github.com/dhruvasagar/vim-table-mode/pull/1
1
EOM
}
generate_reviewjson () {
local prno=$(get_prno "$1")
local reviewjson="/tmp/review.$prno.json"
if [ ! -f "$reviewjson" ]; then
cat > "$reviewjson" <<EOF
{
"body": "Required when using REQUEST_CHANGES or COMMENT for the event parameter. The body text of the pull request review.",
"event": "The review action you want to perform. The review actions include: APPROVE, REQUEST_CHANGES, or COMMENT. By leaving this blank, you set the review action state to PENDING, which means you will need to submit the pull request review when you are ready.",
"comments": [
{
"path": "Required. The relative path to the file that necessitates a review comment.",
"position": "Required. The position value equals the number of lines down from the first '@@' hunk header in the file you want to add a comment. The line just below the '@@' line is position 1, the next line is position 2, and so on. The position in the diff continues to increase through lines of whitespace and additional hunks until the beginning of a new file.",
"body": "Required. Text of the review comment."
}
]
}
EOF
fi
echo "$reviewjson"
}
get_pr_description () {
local file="$2"
local prno=$(get_prno "$1")
local repo=$(get_repo "$1")
local prurl="/repos/$repo/pulls/$prno"
hub api -X GET "$prurl" | jq -r '.title + "\n\n" + .body' >> "$file"
}
get_pr_diff () {
local file="$2"
local prno=$(get_prno "$1")
local repo=$(get_repo "$1")
local prurl="/repos/$repo/pulls/$prno"
hub api -X GET -H Accept:application/vnd.github.v3.diff "$prurl" >> "$file"
}
open_pr () {
local prno=$(get_prno "$1")
local repo=$(get_repo "$1")
local reviewjson="$2"
local prurl="/repos/$repo/pulls/$prno"
local tmpdesc=$(mktemp -t "$prno.XXXX.txt")
local tmpdiff=$(mktemp -t "$prno.XXXX.diff")
get_pr_description "$1" "$tmpdesc"
get_pr_diff "$1" "$tmpdiff"
info "Opening PR $prno"
vim -o "$tmpdesc" "$tmpdiff" \
+"vsplit +set\ foldlevel=99 $reviewjson" +"wincmd L" +"wincmd h" \
+"let g:review_json_path='$reviewjson'"
}
post_review () {
local prno=$(get_prno "$1")
local repo=$(get_repo "$1")
local reviewjson="$2"
info "Submitting review..."
local tmpfile=$(mktemp -t "$prno.XXXX.json")
local reviewurl="/repos/$repo/pulls/$prno/reviews"
hub api -X POST "$reviewurl" --input "$reviewjson" | jq | tee "$tmpfile" | jq
info "Review response saved at $tmpfile"
}
create_review () {
local prurl="$1"
if [ -z "$prurl" ]; then
error 'Missing PR URL'
usage
exit 1
fi
local reviewjson=$(generate_reviewjson "$1")
open_pr "$prurl" "$reviewjson"
post_review "$prurl" "$reviewjson"
}
submit_review () {
prno=$(get_prno "$1")
repo=$(get_repo "$1")
info "Enter review ID: "
read -r reviewid
if [ -z "$reviewid" ]; then
error "Missing review ID"
exit 1
fi
reviewurl="/repos/$repo/pulls/$prno/reviews/$reviewid/events"
info "Enter Review comment: "
read -r review_comment
info "Enter Review Action (APPROVE | REQUEST_CHANGES | COMMENT): "
read -r review_action
info "Submitting Review ID: $reviewid"
hub api -X POST "$reviewurl" \
-F body="$review_comment" \
-F event="$review_action" | jq
}
delete_review () {
prno=$(get_prno "$1")
repo=$(get_repo "$1")
info "Enter review ID: "
read -r reviewid
if [ -z "$reviewid" ]; then
error "Missing review ID"
exit 1
fi
reviewurl="/repos/$repo/pulls/$prno/reviews/$reviewid"
info "Deleting Review ID: $reviewid"
hub api -X DELETE "$reviewurl" | jq
}
invoke () {
func=$1
shift
info "Invoking command $func with args $*"
$func "$@"
}
COMMAND=${1:-"create"}
PR="$2"
if [ "$COMMAND" = "create" ] || [ "$COMMAND" = "submit" ] || [ "$COMMAND" = "delete" ]; then
"${COMMAND}_review" "$PR"
elif [ "$COMMAND" = "invoke" ]; then
invoke "${@:2}"
elif [ "$COMMAND" = "help" ]; then
usage
else
usage
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment