Skip to content

Commit e13a8ad

Browse files
committed
Add github issue functions with 'hub' cli
This commit adds functions for creating and commenting on github issues via the hub cli. Related: conjurinc/ops#492
1 parent 2e80a61 commit e13a8ad

File tree

10 files changed

+411
-13
lines changed

10 files changed

+411
-13
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ files within it's directory.
122122
<td>Git helpers</td>
123123
<td>
124124
<ol>
125+
<li><b>bl_git_available</b>: True if git binary or function is available</li>
126+
<li><b>bl_in_git_repo</b>: True if current directory is a git working directory</li>
127+
<li><b>bl_github_owner_repo</b>: returns $owner/$repo extracted from the url of the origin remote</li>
125128
<li><b>bl_repo_root</b>: Find the root of the current git repo.</li>
126129
<li><b>bl_all_files_in_repo</b>: List files tracked by git.</li>
127130
<li><b>bl_remote_latest_tag</b>: Returns the symbolic name of the latest tag from a remote.</li>
@@ -133,6 +136,21 @@ files within it's directory.
133136
<li><b>bl_cat_gittrees</b>: Returns the contents of .gittrees from the top level of the repo, excluding any comments. Fails if .gittrees is not present.</li>
134137
</ol>
135138
</td>
139+
</tr>
140+
<tr>
141+
<td><a href="github/lib">git</a></td>
142+
<td>Github Related Functions</td>
143+
<td>
144+
<ol>
145+
<li><b>bl_hub_available</b>: True if hub binary or function is available</li>
146+
<li><b>bl_hub_creds_available</b>: True if hub creds are available (file or env vars)</li>
147+
<li><b>bl_hub_check</b>: Preflight check for hub, true if git installed, in git repo, hub installed and hub creds are available</li>
148+
<li><b>bl_hub_download_latest</b>: Download latest hub binary from github and install to ~/bin or specified path</li>
149+
<li><b>bl_hub_issue_number_for_title</b>: Find the issue number for an issue from its title, searches open issues in the current repo. (current repo = workding directory, repo is found by origin remote)</li>
150+
<li><b>bl_hub_add_issue_comment</b>: Add a comment to an issue</li>
151+
<li><b>bl_hub_comment_or_create_issue</b>: Create issue if an issue matching the title doesn't exist. If a match is found, add a comment to it</li>
152+
</ol>
153+
</td>
136154
</tr>
137155
<td><a href="helpers/lib">helpers</a></td>
138156
<td>Bash scripting helpers</td>

filehandling/lib

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ function bl_abs_path() {
77
# generate absolute path from relative path
88
# path : relative filename
99
# return : absolute path
10+
11+
local path
12+
1013
if [[ -z "${1:-}" ]]; then
1114
path="."
1215
else

git/lib

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,43 @@
22

33
: "${BASH_LIB_DIR:?BASH_LIB_DIR must be set. Please source bash-lib/init before other scripts from bash-lib.}"
44

5+
6+
function bl_git_available(){
7+
type git >/dev/null || bl_die "Git binary not found in ${PATH}"
8+
}
9+
10+
function bl_in_git_repo(){
11+
bl_git_available
12+
git status >/dev/null || bl_die "$(pwd) is not within a git repo."
13+
}
14+
15+
function bl_github_owner_repo(){
16+
bl_in_git_repo
17+
remote="${1:-origin}"
18+
19+
git remote -v | grep -q "${remote}" || bl_die "Remote ${remote} doesn't exist for repo ${PWD}"
20+
git remote -v | grep -q "${remote}.*github" || bl_die "Remote ${remote} is not a github remote in repo ${PWD}"
21+
[[ "$(git remote -v |grep "${remote}")" =~ github.com[:/]([^ ]*) ]]
22+
echo "${BASH_REMATCH[1]}"
23+
}
24+
525
# Get the top level of a git repo
626
function bl_repo_root(){
27+
bl_in_git_repo
728
git rev-parse --show-toplevel
829
}
930

1031
# List files tracked by git
1132
function bl_all_files_in_repo(){
33+
bl_in_git_repo
1234
git ls-tree -r HEAD --name-only
1335
}
1436

1537
# Find the latest tag available at a repo url
1638
# Returns tag name, not sha
1739
function bl_remote_latest_tag(){
40+
bl_in_git_repo
41+
1842
local -r remote_url="${1}"
1943
# In ls-remote the ^{} suffix refers to a peeled/dereferenced object.
2044
# eg refs/tags/v0.0.1^{} shows the SHA of the commit that was tagged,
@@ -29,14 +53,19 @@ function bl_remote_latest_tag(){
2953

3054
# Find the SHA of the latests commit to be tagged in a remote repo
3155
function bl_remote_latest_tagged_commit(){
56+
bl_in_git_repo
57+
3258
local -r remote="${1}"
3359
local -r tag="$(bl_remote_latest_tag "${remote}")"
3460
git ls-remote "${remote}" | awk "/refs\/tags\/${tag}\^/{print \$1}"
3561
}
3662

3763
function bl_remote_sha_for_ref(){
64+
bl_in_git_repo
65+
3866
local -r remote="${1}"
3967
local -r ref="${2}"
68+
local peeled_ref
4069

4170
# First try adding ^{} to the ref, incase it's a tag
4271
# and needs peeling. If nothing is found for that,
@@ -55,6 +84,8 @@ function bl_remote_sha_for_ref(){
5584
}
5685

5786
function bl_remote_tag_for_sha(){
87+
bl_in_git_repo
88+
5889
local -r remote="${1}"
5990
local -r sha="${2}"
6091
git ls-remote "${remote}" \
@@ -65,11 +96,13 @@ function bl_remote_tag_for_sha(){
6596
## Minimal git subtree functionality required for tests to pass
6697
# full subtree functionality is not ready for merge.
6798
function bl_gittrees_present(){
99+
bl_in_git_repo
68100
local -r git_trees="$(bl_repo_root)/.gittrees"
69101
[[ -e "${git_trees}" ]]
70102
}
71103

72104
function bl_cat_gittrees(){
105+
bl_in_git_repo
73106
local -r git_trees="$(bl_repo_root)/.gittrees"
74107
local -r subtrees_file_format=".gittrees should contain one subtree per line,\
75108
space seperated with three fields: subtree_path renmote_url remote_name"
@@ -78,6 +111,8 @@ space seperated with three fields: subtree_path renmote_url remote_name"
78111
}
79112

80113
function bl_tracked_files_excluding_subtrees(){
114+
bl_in_git_repo
115+
local subtrees
81116
if bl_gittrees_present; then
82117
subtrees="$(bl_cat_gittrees | awk '{print $1}' | paste -sd '|' -)"
83118
bl_all_files_in_repo | grep -E -v "${subtrees}"

github/lib

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/bin/bash
2+
3+
: "${BASH_LIB_DIR:?BASH_LIB_DIR must be set. Please source bash-lib/init before other scripts from bash-lib.}"
4+
5+
function bl_hub_available(){
6+
# type instead of which, so it can be stubbed in tests
7+
type hub >/dev/null || bl_die "hub (github cli) binary not found, please install it via your package manager or use bl_hub_download_latest."
8+
}
9+
10+
function bl_hub_creds_available(){
11+
config_file="${HUB_CONFIG:-${HOME}/.config/hub}"
12+
[[ -n "${GITHUB_USER:-}" ]] && [[ -n "${GITHUB_TOKEN:-}" ]] && return
13+
[[ -e "${config_file}" ]] && return
14+
bl_die "No credentials found for (git)hub please set GITHUB_USER and GITHUB_TOKEN or create ~/.config/hub"
15+
}
16+
17+
# shellcheck disable=SC2119
18+
function bl_hub_check(){
19+
bl_in_git_repo
20+
bl_hub_available
21+
bl_hub_creds_available
22+
}
23+
24+
function bl_hub_download_latest(){
25+
local install_dir="${1:-${HOME}/bin}"
26+
local os_arch="${2:-}"
27+
local tmpdir=".hubdl"
28+
local path
29+
local download_url
30+
local bin_path
31+
32+
if [[ -z "${os_arch}" ]]; then
33+
if [[ "${OSTYPE}" =~ "darwin" ]]; then
34+
os_arch="darwin-amd64"
35+
else
36+
os_arch="linux-amd64"
37+
fi
38+
fi
39+
40+
path="$(curl -L https://github.com/github/hub/releases/latest |grep -o '[^"]*hub-'${os_arch}'[^"]*')"
41+
download_url="https://github.com/${path}"
42+
43+
bin_path="${install_dir}/hub"
44+
mkdir -p "${install_dir}"
45+
46+
mkdir -p "${tmpdir}"
47+
bl_spushd "${tmpdir}"
48+
curl -L "${download_url}" > hub.tgz
49+
tar xvf hub.tgz
50+
mv ./*/bin/hub "${bin_path}"
51+
bl_spopd
52+
rm -rf "${tmpdir}"
53+
54+
bl_info "${download_url} --> ${bin_path}"
55+
}
56+
57+
function bl_hub_issue_number_for_title(){
58+
local title="${1}"
59+
bl_hub_check
60+
hub issue \
61+
|grep "${title}" \
62+
|awk -F'[ #]+' '{print $2}'
63+
}
64+
65+
function bl_hub_add_issue_comment(){
66+
local issue_number="${1}"
67+
local comment="${2}"
68+
69+
bl_hub_check
70+
71+
[[ -n "${comment}" ]] || die "bl_hub_add_issue_comment: Comment must not be empty"
72+
hub issue show "${issue_number}" >/dev/null || die "Github Issue number ${issue_number} isn't valid for repo $(pwd)"
73+
74+
owner_repo="$(bl_github_owner_repo)"
75+
hub api "repos/${owner_repo}/issues/${issue_number}/comments" --field body="${comment}"
76+
77+
bl_info "Added comment: \"${comment}\" to https://github.com/${owner_repo}/issues/${issue_number}"
78+
}
79+
80+
81+
function bl_hub_comment_or_create_issue(){
82+
local title="${1}"
83+
local message="${2}"
84+
local issue_number
85+
local issue_url
86+
bl_hub_check
87+
88+
issue_number="$(bl_hub_issue_number_for_title "${title}" ||:)"
89+
90+
if [[ -z "${issue_number}" ]]; then
91+
# issue doesn't exist create it
92+
issue_url="$(hub issue create -m "${title}
93+
94+
${message}")"
95+
96+
# Example issue url: https://github.com/{owner}/{repo}/issues/{issue number}"
97+
# To find the issue number, split on / and take the last field
98+
issue_number="$(awk -F'/' '{print $NF}' <<<"${issue_url}" )"
99+
100+
bl_info "Created issue: https://github.com/$(bl_github_owner_repo)/issues/${issue_number} with title \"${title}\""
101+
else
102+
bl_info "Found existing issue for title \"${title}\": https://github.com/$(bl_github_owner_repo)/issues/${issue_number}"
103+
bl_hub_add_issue_comment "${issue_number}" "${message}"
104+
fi
105+
echo "${issue_number}"
106+
}
107+
108+

helpers/lib

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,23 @@ function bl_retry {
3636
# Maxiumum amount of fixed delay between attempts
3737
# a random value will still be added.
3838
local -r MAX_BACKOFF=30
39+
local exit
40+
local count
41+
local retries
42+
local backoff
3943

4044
if [[ ${#} -lt 2 ]]; then
4145
bl_die "retry usage: retry <retries> <command>"
4246
fi
4347

44-
local retries=$1
48+
retries=$1
4549
shift
4650

4751
if ! bl_is_num "${retries}"; then
4852
bl_die "Invalid number of retries: ${retries} for command '${*}'".
4953
fi
5054

51-
local count=0
55+
count=0
5256
until eval "$@"; do
5357
# Command failed, otherwise until would have skipped the loop
5458

@@ -84,6 +88,9 @@ function bl_retry_constant {
8488

8589
local retries=$1; shift
8690
local interval=$1; shift
91+
local count
92+
local exit
93+
local interval
8794

8895
if ! bl_is_num "${retries}"; then
8996
bl_die "Invalid number of retries: ${retries} for command '${*}'"
@@ -93,7 +100,7 @@ function bl_retry_constant {
93100
bl_die "Invalid interval in seconds: ${retries} for command '${*}'".
94101
fi
95102

96-
local count=0
103+
count=0
97104
until eval "$@"; do
98105
# Command failed, otherwise until would have skipped the loop
99106

init

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ BASH_LIB_DIR="${BASH_LIB_DIR_RELATIVE}"
2626

2727
# Load the filehandling module for the abspath
2828
# function
29-
for lib in helpers logging filehandling git k8s test-utils; do
29+
for lib in helpers logging filehandling git github k8s test-utils; do
3030
. "${BASH_LIB_DIR_RELATIVE}/${lib}/lib"
3131
done
3232

logging/lib

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function bl_announce() {
1414
}
1515

1616
function bl_check_log_level(){
17-
level="${1}"
17+
local level="${1}"
1818
if [[ ${level} =~ debug|info|warn|error|fatal ]];
1919
then
2020
return 0
@@ -27,16 +27,16 @@ function bl_check_log_level(){
2727
function bl_log {
2828
declare -A BASH_LIB_LOG_LEVELS=( [debug]=1 [info]=2 [warn]=3 [error]=4 [fatal]=5 )
2929
declare -A BASH_LIB_LOG_COLOURS=( [debug]="0;37;40" [info]="0;36;40" [warn]="0;33;40" [error]="1;31;40" [fatal]="1;37;41" )
30-
runtime_log_level="${BASH_LIB_LOG_LEVEL}"
31-
write_log_level="${1}"
32-
msg="${2}"
33-
out="${3:-stdout}"
30+
local runtime_log_level="${BASH_LIB_LOG_LEVEL}"
31+
local write_log_level="${1}"
32+
local msg="${2}"
33+
local out="${3:-stdout}"
3434

3535
bl_check_log_level "${runtime_log_level}"
3636
bl_check_log_level "${write_log_level}"
3737

38-
runtime_level_num="${BASH_LIB_LOG_LEVELS[${runtime_log_level}]}"
39-
write_level_num="${BASH_LIB_LOG_LEVELS[${write_log_level}]}"
38+
local runtime_level_num="${BASH_LIB_LOG_LEVELS[${runtime_log_level}]}"
39+
local write_level_num="${BASH_LIB_LOG_LEVELS[${write_log_level}]}"
4040

4141
if (( write_level_num < runtime_level_num )); then
4242
return

0 commit comments

Comments
 (0)