|
#!/bin/zsh |
|
set -e |
|
set -o pipefail |
|
|
|
base=${0:h:A} |
|
repo=$base/repo |
|
pulls=$base/github |
|
|
|
if [[ -z $GITHUB_TOKEN && -e .env ]]; then |
|
source .env |
|
fi |
|
|
|
if [[ -z $GITHUB_TOKEN ]]; then |
|
echo No GITHUB_TOKEN present |
|
return 1 |
|
fi |
|
|
|
if [[ "$1" = --help ]]; then |
|
echo "Usage: $0 [commit]" >&2 |
|
echo "Use 'commit' if you want to apply the label changes" >&2 |
|
exit |
|
fi |
|
|
|
URI=https://api.github.com |
|
API_VERSION=v3 |
|
API_HEADER="Accept: application/vnd.github.${API_VERSION}+json" |
|
AUTH_HEADER="Authorization: token ${GITHUB_TOKEN}" |
|
|
|
|
|
typeset -A LABELS |
|
LABELS=( |
|
core 'Area: core' |
|
init 'Area: init' |
|
install 'Area: installer' |
|
update 'Area: updater' |
|
plugin 'Area: plugin' |
|
theme 'Area: theme' |
|
uninstall 'Area: uninstaller' |
|
new_plugin 'New: plugin' |
|
new_theme 'New: theme' |
|
plugin_aws 'Plugin: aws' |
|
plugin_git 'Plugin: git' |
|
plugin_mercurial 'Plugin: mercurial' |
|
plugin_tmux 'Plugin: tmux' |
|
alias 'Topic: alias' |
|
bindkey 'Topic: bindkey' |
|
completion 'Topic: completion' |
|
documentation 'Type: documentation' |
|
conflicts 'Status: conflicts' |
|
) |
|
|
|
has_conflicts() { |
|
git -c user.name=bot -c user.email=b@o.t \ |
|
merge --no-commit --no-ff $GITHUB_SHA &>/dev/null && ret=1 || ret=0 |
|
git merge --abort &>/dev/null |
|
return $ret |
|
} |
|
|
|
triage_pull_request() { |
|
local -aU labels files plugins themes |
|
local file plugin theme diff |
|
|
|
# Changed files |
|
files=("${(f)$(git diff --name-only HEAD...$GITHUB_SHA)}") |
|
|
|
# Filter files to only obtain core files (inside 'lib/' or 'tools/') |
|
if (( ${files[(I)lib/*|tools/*]} > 0 )); then |
|
labels+=($LABELS[core]) |
|
fi |
|
|
|
# Filter files to only obtain changed plugins ('plugins/$name') |
|
plugins=(${(M)files#plugins/*/}) |
|
if (( $#plugins > 0 )); then |
|
labels+=($LABELS[plugin]) |
|
for plugin ($plugins); do |
|
# If the plugin doesn't exist mark it as new |
|
[[ ! -e "$plugin" ]] && labels+=($LABELS[new_plugin]) |
|
done |
|
fi |
|
|
|
# Filter files to only obtain changed themes ('themes/$name.zsh-theme') |
|
themes=(${(M)files#themes/*.zsh-theme}) |
|
if (( $#themes > 0 )); then |
|
labels+=($LABELS[theme]) |
|
for theme ($themes); do |
|
[[ ! -e "$theme" ]] && labels+=($LABELS[new_theme]) |
|
done |
|
fi |
|
|
|
# Loop over the rest of the files for miscellaneous tests |
|
for file ($files); do |
|
case $file in |
|
oh-my-zsh.(sh|.zsh)) labels+=($LABELS[init]) ;; |
|
tools/*upgrade.sh) labels+=($LABELS[update]) ;; |
|
tools/install.sh) labels+=($LABELS[install]) ;; |
|
tools/uninstall.sh) labels+=($LABELS[uninstall]) ;; |
|
plugins/aws/*) labels+=($LABELS[plugin_aws]) ;; |
|
plugins/git/*) labels+=($LABELS[plugin_git]) ;; |
|
plugins/mercurial/*) labels+=($LABELS[plugin_mercurial]) ;; |
|
plugins/tmux/*) labels+=($LABELS[plugin_tmux]) ;; |
|
(|*/)README.*) labels+=($LABELS[documentation]) ;; |
|
esac |
|
|
|
case ${file:t} in |
|
*.zsh) # check if or aliases or bindkeys are added, deleted or modified |
|
diff=$(git diff HEAD...$GITHUB_SHA -- $file) |
|
grep -q -E '^[-+] *alias ' <<< $diff && labels+=($LABELS[alias]) |
|
grep -q -E '^[-+] *bindkey ' <<< $diff && labels+=($LABELS[bindkey]) ;; |
|
_*) # check if completion files are added, deleted or modified |
|
labels+=($LABELS[completion]) ;; |
|
esac |
|
done |
|
|
|
# Print labels in ascending order and quote for labels with spaces |
|
if (( $#labels > 0 )); then |
|
print -l ${(oq)labels} |
|
fi |
|
} |
|
|
|
process() { |
|
local number=$1 jsonfile=$2 run=0 |
|
[[ $3 = commit ]] && run=1 |
|
|
|
local JSON |
|
JSON=$(jq ".data.repository.pullRequests.nodes | .[] | select(.number | . and contains($number))" $jsonfile) |
|
|
|
local -aU current_labels |
|
current_labels=("${(f)$(jq --raw-output '.labels.nodes | .[].name' <<< $JSON)}") |
|
|
|
local sha=$(jq --raw-output .headRefOid <<< $JSON) |
|
GITHUB_SHA=$sha |
|
|
|
# Creates an array of labels to apply to the PR being analyzed |
|
local -aU labels |
|
labels=("${(f)$(triage_pull_request)}") |
|
|
|
# Check if PR has conflicts with master |
|
if has_conflicts; then |
|
# echo Pull request with conflicts |
|
labels+=($LABELS[conflicts]) |
|
# Check if PR has "conflicts" label |
|
elif (( $current_labels[(I)$LABELS[conflicts]] > 0 )); then |
|
local replace=1 |
|
fi |
|
|
|
if (( $+replace )); then |
|
# Add current labels to the set of labels to add (except the "conflicts" label) |
|
labels+=(${current_labels:#$LABELS[conflicts]}) |
|
else |
|
# Remove current labels from the set of labels to add |
|
labels=(${labels:|current_labels}) |
|
fi |
|
|
|
# Update labels |
|
if (( $#labels > 0 )); then |
|
data=$(print -l $labels | jq -cnR '{ labels: [inputs | select(length>0)] }') |
|
|
|
echo $'\n'Pull request "#$number": https://github.com/ohmyzsh/ohmyzsh/pull/$number |
|
if (( $+replace )); then |
|
# Replace labels: https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue |
|
echo "Old labels:" ${(j:, :)${(qq)current_labels}} |
|
echo "Replacing labels to:" ${(j:, :)${(qq)labels}}... |
|
|
|
(( $run )) || return 0 |
|
|
|
curl -XPUT -sSL \ |
|
-H "${AUTH_HEADER}" \ |
|
-H "${API_HEADER}" \ |
|
--data $data \ |
|
"${URI}/repos/ohmyzsh/ohmyzsh/issues/${number}/labels" |
|
else |
|
# Add labels: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue |
|
echo "Adding labels to PR #$number:" ${(j:, :)${(qq)labels}}... |
|
|
|
(( $run )) || return 0 |
|
|
|
curl -XPOST -sSL \ |
|
-H "${AUTH_HEADER}" \ |
|
-H "${API_HEADER}" \ |
|
--data $data \ |
|
"${URI}/repos/ohmyzsh/ohmyzsh/issues/${number}/labels" |
|
fi |
|
|
|
sleep 1 # wait before next API call |
|
else |
|
# echo "No labels added to PR #$number." |
|
fi |
|
} |
|
|
|
pushd $repo |
|
|
|
for jsonfile in ${pulls:A}/*.json; do |
|
echo Processing PRs from ${jsonfile:t}... |
|
while read number; do |
|
process $number $jsonfile $1 |
|
done < <(jq '.data.repository.pullRequests.nodes | .[].number' $jsonfile) |
|
echo |
|
done |
|
|
|
popd |