forked from vitorgalvao/tiny-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprfixmaster
More file actions
executable file
·155 lines (129 loc) · 4.74 KB
/
Copy pathprfixmaster
File metadata and controls
executable file
·155 lines (129 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/bash
readonly program="$(basename "${0}")"
readonly issue_number_file='/tmp/prfixmaster_issue_number_save'
remote='upstream' # use 'upstream' as default remote
squash_changes='true' # by default, squash changes
# check if 'ghi' is installed and configured
if [[ ! $(which 'ghi') ]] || ! security find-internet-password -s github.com -l 'ghi token' &> /dev/null; then
echo -e "$(tput setaf 1)
This script requires 'ghi' installed and configured.
If you have [Homebrew](http://brew.sh), you can install it with 'brew install ghi'.
To configure it, run 'ghi config --auth <username>'. Your Github password will be required, but is never stored.
$(tput sgr0)" | sed -E 's/ {4}//' >&2
exit 1
fi
syntax_error() {
echo -e "${program}: ${1}\nTry \`${program} --help\` for more information." >&2
exit 1
}
usage() {
echo "
Usage:
${program} [options] <github_pull_request_url>
Options:
-r <remote>, --remote <remote> Use to specify a remote to pull from and push to (defaults to 'upstream').
-c, --continue Use after making your fixes, to push your changes and close the issue with a message. If you use it with uncommitted changes, they'll all be squashed (fixup) into the original patch; else your commits will be preserved.
-n, --no-squash Do not squash commits before pushing.
-h, --help Show this help.
" | sed -E 's/^ {4}//'
}
# read remote from git config
configured_remote="$(git config --get tiny-scripts.remote)"
if [[ -n "${configured_remote}" ]]; then
remote="${configured_remote}"
fi
# available flags
args=()
while [[ "${1}" ]]; do
case "${1}" in
-h | --help)
usage
exit 0
;;
-r | --remote)
remote="${2}"
shift
;;
-c | --continue)
push_changes='true'
;;
-n | --no-squash)
squash_changes='false'
;;
--)
shift
args+=("${@}")
break
;;
-*)
syntax_error "unrecognized option: ${1}"
;;
*)
args+=("${1}")
;;
esac
shift
done
set -- "${args[@]}"
check_repo() {
local_repo=$(git remote show origin -n | grep 'Fetch URL:' | sed 's|.*/||;s|\.git$||')
remote_repo=$(sed -E 's|.*/(.*)/pull.*|\1|' <<< "${url}")
if [[ "${local_repo}" != "${remote_repo}" ]]; then
echo -e "\n$(tput setaf 1)You're trying to pull from '${remote_repo}' but you're on '${local_repo}'.$(tput sgr0)\n"
exit 1
fi
}
pull_remote() { # pull changes if local branch is behind
last_commit_local=$(git rev-parse refs/heads/master)
last_commit_remote=$(git ls-remote "${remote}" --heads refs/heads/master | perl -pe 's/\s.*//')
[[ "${last_commit_local}" != "${last_commit_remote}" ]] && git pull --rebase "${remote}" master
}
apply_patch() {
url=$(perl -pe 's|(.*/pull/\d+).*|\1|' <<< "${1}") # clean url of extraneous information
issue_number=$(sed 's|.*/||' <<< "${url}")
patch_url="${url}.patch" # github pull request url, ending in '.patch'
check_repo
current_branch=$(git rev-parse --abbrev-ref HEAD)
[[ "${current_branch}" != 'master' ]] && git checkout master
pull_remote
curl --location --silent "${patch_url}" | git am --3way # get and apply patch
echo "${issue_number}" > "${issue_number_file}" # save issue number
echo "
Make your changes and run
${program} -c
" | sed -E 's/^ {2}//'
}
rebase_squash() {
base_commit="${1}"
echo "Squashing changes into a single commit…"
GIT_EDITOR="perl -pi -e 's/^pick\b/squash/ unless 1 .. 1'" git rebase --interactive "${base_commit}"
}
push_and_close() {
original_issue="$(cat ${issue_number_file})"
uncommitted_changes="$(git status --porcelain --untracked-files=no)"
# squash your fixes into the last commit, if there are uncommitted changes
if [[ "${uncommitted_changes}" ]]; then
git commit --all --allow-empty-message --message ''
git reset --soft @~
git commit --amend -C HEAD
fi
[[ "${squash_changes}" == 'true' ]] && rebase_squash "${remote}/master"
amend_message "${original_issue}"
# push and close issue
pull_remote
git push "${remote}" master && ghi close --message "Thank you for the contribution. It needed some fixes, so they were made in ${last_commit_local}. Your contribution is still included (and still credited to you), with the appropriate modifications. Please feel free to ask about any of the changes." "${original_issue}"
}
amend_message() {
issue_number="${1}"
amended_message=$(git log --format=%B -n1 | sed "1 s/$/ (#${issue_number})/")
echo "Amending commit message with issue number (#${issue_number})…"
git commit --amend -F <(echo "${amended_message}")
}
if [[ "${1}" =~ https://github.com/* ]]; then
apply_patch "${1}"
elif [[ "${push_changes}" == 'true' ]]; then
push_and_close
else
usage
exit 1
fi