-
Notifications
You must be signed in to change notification settings - Fork 36
/
delete-old-branches
executable file
·136 lines (111 loc) · 4.41 KB
/
delete-old-branches
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
#!/bin/bash
set -eo pipefail
[[ -n ${INPUT_REPO_TOKEN} ]] || { echo "Please set the REPO_TOKEN input"; exit 1; }
[[ -n ${INPUT_DATE} ]] || { echo "Please specify a suitable date input for branch filtering"; exit 1; }
REPO="${GITHUB_REPOSITORY}"
DATE=${INPUT_DATE}
DRY_RUN=${INPUT_DRY_RUN:-true}
DELETE_TAGS=${INPUT_DELETE_TAGS:-false}
MINIMUM_TAGS=${INPUT_MINIMUM_TAGS:-0}
DEFAULT_BRANCHES=${INPUT_DEFAULT_BRANCHES:-main,master}
EXCLUDE_BRANCH_REGEX=${INPUT_EXTRA_PROTECTED_BRANCH_REGEX:-^$}
EXCLUDE_TAG_REGEX=${INPUT_EXTRA_PROTECTED_TAG_REGEX:-^$}
EXCLUDE_OPEN_PR_BRANCHES=${INPUT_EXCLUDE_OPEN_PR_BRANCHES:-true}
# used for GitHub CLI authentication
export GITHUB_TOKEN=${INPUT_REPO_TOKEN}
echo "was_dry_run=${DRY_RUN}" >> "$GITHUB_OUTPUT"
deleted_branches=()
default_branch_protected() {
local br=${1}
local default_branches
default_branches=$(echo "${DEFAULT_BRANCHES}" | tr "," "\n")
for default_branch in $default_branches; do
if [[ "${br}" == "${default_branch}" ]]; then
return 0
fi
done
return 1
}
branch_protected() {
local br=${1}
protected=$(gh api "repos/${REPO}/branches/${br}" --jq '.protected')
# If we got null then something else happened (like no access error etc) so
# we can't determine the status for the branch
case ${protected} in
null) echo "Unable to determine status for branch: ${br}"; return 0 ;;
true) return 0 ;;
*) return 1 ;;
esac
}
extra_branch_or_tag_protected() {
local br=${1} ref="${2}"
if [[ "${ref}" == "branch" ]]; then
echo "${br}" | grep -qE "${EXCLUDE_BRANCH_REGEX}"
elif [[ "${ref}" == "tag" ]]; then
echo "${br}" | grep -qE "${EXCLUDE_TAG_REGEX}"
fi
return $?
}
is_pr_open_on_branch() {
if [[ "${EXCLUDE_OPEN_PR_BRANCHES}" == false ]]; then
return 1
fi
local br=${1}
open_prs_branches=$(gh api "repos/${REPO}/pulls" --jq '.[].head.ref' --paginate)
for pr_br in ${open_prs_branches}; do
if [[ "${pr_br}" == "${br}" ]]; then
return 0
fi
done
return 1
}
delete_branch_or_tag() {
local br=${1} ref="${2}" sha="${3}"
deleted_branches+=("${br}")
echo "Deleting: ${br}"
echo "To recreate run: git branch '${br}' '${sha}'"
if [[ "${DRY_RUN}" == false ]]; then
status=$(gh api --method DELETE "repos/${REPO}/git/refs/${ref}/${br}" &> debug.log && echo ok || echo failed)
case ${status} in
ok) ;;
*) echo "Deletion of branch ${br} failed with http_status=${status}"
echo "===== Dumping log ====="
[[ -f debug.log ]] && cat debug.log
;;
esac
else
echo "dry-run mode. Nothing changed!"
fi
}
main() {
# fetch history etc
local sha
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
git fetch --prune --unshallow --tags
for br in $(git ls-remote -q --heads --refs | sed "s@^.*heads/@@"); do
if [[ -z "$(git log --oneline -1 --since="${DATE}" origin/"${br}")" ]]; then
sha=$(git show-ref -s "origin/${br}")
default_branch_protected "${br}" && echo "branch: ${br} is a default branch. Won't delete it" && continue
branch_protected "${br}" && echo "branch: ${br} is likely protected. Won't delete it" && continue
extra_branch_or_tag_protected "${br}" "branch" && echo "branch: ${br} is explicitly protected and won't be deleted" && continue
is_pr_open_on_branch "${br}" && echo "branch: ${br} has an open pull request and won't be deleted" && continue
delete_branch_or_tag "${br}" "heads" "${sha}"
fi
done
echo "deleted_branches=${deleted_branches[*]}" >> "$GITHUB_OUTPUT"
if [[ "${DELETE_TAGS}" == true ]]; then
local tag_counter=1
for br in $(git ls-remote -q --tags --refs | sed "s@^.*tags/@@" | sort -rn); do
if [[ -z "$(git log --oneline -1 --since="${DATE}" "${br}")" ]]; then
if [[ ${tag_counter} -gt ${MINIMUM_TAGS} ]]; then
extra_branch_or_tag_protected "${br}" "tag" && echo "tag: ${br} is explicitly protected and won't be deleted" && continue
delete_branch_or_tag "${br}" "tags"
else
echo "Not deleting tag ${br} due to minimum tag requirement(min: ${MINIMUM_TAGS})"
((tag_counter+=1))
fi
fi
done
fi
}
main "$@"