Skip to content

Commit 1a17d11

Browse files
authored
feat: add 3 new functions is_boolean, return_mac_architecture and install_jq (#4)
1 parent 31dfb08 commit 1a17d11

File tree

3 files changed

+292
-3
lines changed

3 files changed

+292
-3
lines changed

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2025-11-23T00:19:45Z",
6+
"generated_at": "2025-11-26T21:55:36Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -82,7 +82,7 @@
8282
"hashed_secret": "1de54cf4c9c5e2b8b9aef885aebefb5c1be33332",
8383
"is_secret": false,
8484
"is_verified": false,
85-
"line_number": 136,
85+
"line_number": 207,
8686
"type": "Secret Keyword",
8787
"verified_result": null
8888
}

README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,77 @@ check_required_bins git jq
115115

116116
<!------------------------------------------------>
117117

118+
<details>
119+
<summary>install_jq</summary>
120+
121+
Installs jq binary.
122+
123+
**Environment Variables:**
124+
- `VERBOSE`: If set to true, print verbose output (optional, defaults to false)
125+
126+
**Arguments:**
127+
- `$1`: version of jq to install (optional, defaults to latest). Example format of valid version is "1.8.1"
128+
- `$2`: location to install jq to (optional, defaults to /usr/local/bin)
129+
- `$3`: if set to true, skips installation if jq is already detected (optional, defaults to true)
130+
- `$4`: the exact url to download jq from (optional, defaults to https://github.com/jqlang/jq/releases/latest/download/jq-${os}-${arch})
131+
132+
**Returns:**
133+
- `0` - Success (jq installed successfully)
134+
- `1` - Failure (installation failed)
135+
- `2` - Failure (incorrect usage of function)
136+
137+
**Usage:**
138+
```bash
139+
install_jq "latest" "/usr/local/bin" "true"
140+
```
141+
142+
<!------------------------------------------------>
143+
144+
</details>
145+
<details>
146+
<summary>is_boolean</summary>
147+
148+
Determine if value is a boolean.
149+
150+
**Arguments:**
151+
- `$1`: value to check (required)
152+
153+
**Returns:**
154+
- `0` - Success (value is a boolean - true, True, false or False)
155+
- `1` - Failure (value is not a boolean)
156+
- `2` - Failure (incorrect usage of function)
157+
158+
**Usage:**
159+
```bash
160+
is_boolean "true"
161+
```
162+
</details>
163+
164+
<!------------------------------------------------>
165+
166+
<details>
167+
<summary>return_mac_architecture</summary>
168+
169+
Returns the architecture of the MacOS.
170+
171+
**Arguments:** n/a
172+
173+
**Returns:**
174+
- `0` - Success
175+
- `"amd64"` - if the OS is macOS and the CPU is Intel
176+
- `"arm64"` - if the OS is macOS and the CPU is Apple Silicon
177+
- `2` - Failure (Did not detect MacOS)
178+
179+
**Usage:**
180+
```bash
181+
arch=$(return_mac_architecture)
182+
```
183+
</details>
184+
185+
<!------------------------------------------------>
186+
187+
<!------------------------------------------------>
188+
118189
## [ibmcloud/iam](ibmcloud/iam.sh)
119190
<details>
120191
<summary>generate_iam_bearer_token</summary>

common/common.sh

Lines changed: 219 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ check_required_bins() {
174174
done
175175

176176
if (( ${#missing[@]} )); then
177-
echo "Missing binaries: ${missing[*]}" >&2
177+
if [ "${verbose}" = true ]; then
178+
echo "Missing binaries: ${missing[*]}" >&2
179+
fi
178180
return ${RETURN_CODE_ERROR}
179181
fi
180182

@@ -184,11 +186,178 @@ check_required_bins() {
184186
return ${RETURN_CODE_SUCCESS}
185187
}
186188

189+
#===============================================================
190+
# FUNCTION: is_boolean
191+
# DESCRIPTION: Determine is value is a boolean.
192+
#
193+
# ARGUMENTS:
194+
# - $1: value to check (required)
195+
#
196+
# RETURNS:
197+
# 0 - Success (value is a boolean - true, True, false or False)
198+
# 1 - Failure (value is not a boolean)
199+
# 2 - Failure (incorrect usage of function)
200+
#
201+
# USAGE: is_boolean <value>
202+
#===============================================================
203+
is_boolean() {
204+
205+
# Validate an arg has been provided
206+
if [ $# -ne 1 ]; then
207+
echo "Error: is_boolean requires exactly 1 argument, but $# were provided" >&2
208+
echo "Usage: is_boolean <value>" >&2
209+
exit ${RETURN_CODE_ERROR_INCORRECT_USAGE}
210+
fi
211+
212+
if [[ $1 =~ ^([Tt]rue|[Ff]alse)$ ]]; then
213+
return ${RETURN_CODE_SUCCESS}
214+
else
215+
return ${RETURN_CODE_ERROR}
216+
fi
217+
}
218+
219+
#===============================================================
220+
# FUNCTION: return_mac_architecture
221+
# DESCRIPTION: Returns the architecture of the MacOS
222+
#
223+
# RETURNS:
224+
# 0 - Success
225+
# - "amd64" - if the OS is macOS and the CPU is Intel
226+
# - "arm64" - if the OS is macOS and the CPU is Apple Silicon
227+
# 2 - Failure (Did not detect MacOS)
228+
#
229+
# USAGE: return_mac_architecture
230+
#===============================================================
231+
return_mac_architecture() {
232+
233+
local arch="arm64"
234+
local cpu
235+
if [[ ${OSTYPE} == 'darwin'* ]]; then
236+
cpu="$(sysctl -a | grep machdep.cpu.brand_string)"
237+
if [[ "${cpu}" == 'machdep.cpu.brand_string: Intel'* ]]; then
238+
# macOS on Intel architecture
239+
arch="amd64"
240+
fi
241+
else
242+
echo "Unsupported OS: ${OSTYPE}" >&2
243+
return ${RETURN_CODE_ERROR_INCORRECT_USAGE}
244+
fi
245+
echo ${arch}
246+
}
247+
248+
#===============================================================
249+
# FUNCTION: install_jq
250+
# DESCRIPTION: Installs jq binary
251+
#
252+
# ENVIRONMENT VARIABLES:
253+
# - VERBOSE: If set to true, print verbose output (optional, defaults to false)
254+
#
255+
# ARGUMENTS:
256+
# - $1: version of jq to install (optional, defaults to latest). Example format of valid version is "1.8.1".
257+
# - $2: location to install jq to (optional, defaults to /usr/local/bin)
258+
# - $3: if set to true, skips installation if jq is already detected (optional, defaults to true)
259+
# - $4: the exact url to download jq from (optional, defaults to https://github.com/jqlang/jq/releases/latest/download/jq-${os}-${arch})
260+
#
261+
# RETURNS:
262+
# 0 - Success (jq installation successful)
263+
# 1 - Failure (jq installation failed)
264+
# 2 - Failure (incorrect usage of function)
265+
#
266+
# USAGE: install_jq "latest" "/usr/local/bin" "true"
267+
#===============================================================
268+
install_jq() {
269+
270+
local version=${1:-"latest"} # default to latest if not specified
271+
local location=${2:-"/usr/local/bin"}
272+
local skip_if_detected=${3:-"true"}
273+
local link_to_binary=${4:-""}
274+
local verbose=${VERBOSE:-false}
275+
276+
# Validate $3 arg is boolean
277+
if ! is_boolean "${skip_if_detected}"; then
278+
echo "Unsupported value detected for the 3rd argument. Only 'true' or 'false' is supported. Found: ${skip_if_detected}." >&2
279+
return ${RETURN_CODE_ERROR_INCORRECT_USAGE}
280+
fi
281+
282+
# return 0 if jq already installed and skip_if_detected is true
283+
if [ "${skip_if_detected}" == "true" ]; then
284+
if check_required_bins jq; then
285+
if [ "${verbose}" = true ]; then
286+
echo "Found jq already installed. Taking no action."
287+
fi
288+
return ${RETURN_CODE_SUCCESS}
289+
fi
290+
fi
291+
# ensure curl is installed
292+
check_required_bins curl || return $?
293+
294+
# strip "v" prefix if it exists in version
295+
if [[ "${version}" == "v"* ]]; then
296+
version="${version#v}"
297+
fi
298+
299+
# if no link to binary passed, determine the download link based on detected os and arch
300+
if [ -z "${link_to_binary}" ]; then
301+
# determine the OS and architecture
302+
local os="linux"
303+
local arch="amd64"
304+
if [[ ${OSTYPE} == 'darwin'* ]]; then
305+
arch=$(return_mac_architecture)
306+
fi
307+
# determine download link to binary
308+
link_to_binary="https://github.com/jqlang/jq/releases/download/jq-${version}/jq-${os}-${arch}"
309+
if [ "${version}" = "latest" ]; then
310+
link_to_binary="https://github.com/jqlang/jq/releases/latest/download/jq-${os}-${arch}"
311+
fi
312+
fi
313+
if [ "${verbose}" = true ]; then
314+
echo "Using download link: ${link_to_binary}"
315+
fi
316+
317+
# use sudo if needed
318+
local arg=""
319+
if ! [ -w "${location}" ]; then
320+
echo "No write permission to ${location}. Using sudo..."
321+
arg=sudo
322+
fi
323+
324+
# remove if already exists
325+
${arg} rm -f "${location}/jq"
326+
327+
# download binary
328+
set +e
329+
if ! ${arg} curl --silent \
330+
--connect-timeout 5 \
331+
--max-time 10 \
332+
--retry 3 \
333+
--retry-delay 2 \
334+
--retry-connrefused \
335+
--fail \
336+
--show-error \
337+
--location \
338+
--output "${location}/jq" \
339+
"${link_to_binary}"
340+
then
341+
echo "Failed to download ${link_to_binary}"
342+
return ${RETURN_CODE_ERROR}
343+
fi
344+
set -e
345+
346+
# make executable
347+
${arg} chmod +x "${location}/jq"
348+
349+
if [ "${verbose}" = true ]; then
350+
echo "Successfully completed installation to ${location}/jq"
351+
fi
352+
return ${RETURN_CODE_SUCCESS}
353+
}
354+
187355
#===============================================================
188356
# UNIT TESTS
189357
#===============================================================
190358

191359
_test() {
360+
local make_api_calls="${MAKE_API_CALLS:-false}"
192361
printf "%s\n\n" "Running tests.."
193362

194363
# check_env_vars
@@ -223,6 +392,55 @@ _test() {
223392
assert_fail "${rc}"
224393
printf "%s\n\n" "✅ PASS"
225394

395+
# is_boolean
396+
# -----------------------------------
397+
# - Test valid booleans
398+
for i in "true" "false" "True" "False"; do
399+
printf "%s\n" "Running 'is_boolean $i'"
400+
rc=${RETURN_CODE_SUCCESS}
401+
is_boolean $i >/dev/null 2>&1 || rc=$?
402+
assert_pass "${rc}"
403+
printf "%s\n\n" "✅ PASS"
404+
done
405+
406+
# - Test non valid boolean
407+
printf "%s\n" "Running 'is_boolean not_a_boolean'"
408+
rc=${RETURN_CODE_SUCCESS}
409+
is_boolean not_a_boolean >/dev/null 2>&1 || rc=$?
410+
assert_fail "${rc}"
411+
printf "%s\n\n" "✅ PASS"
412+
413+
# install_jq
414+
# -----------------------------------
415+
if [ "${make_api_calls}" = true ]; then
416+
# Check if jq already exists on $PATH
417+
local jq_installed=true
418+
check_required_bins jq || jq_installed=false
419+
420+
# - Test installing jq using defaults (when it does not already exist)
421+
if [ ${jq_installed} = false ]; then
422+
printf "%s\n" "Running 'install_jq' (when jq does not already exists)"
423+
rc=${RETURN_CODE_SUCCESS}
424+
install_jq >/dev/null 2>&1 || rc=$?
425+
assert_pass "${rc}"
426+
printf "%s\n\n" "✅ PASS"
427+
fi
428+
429+
# - Test installing it when jq already exists with default args (should be skipped)
430+
printf "%s\n" "Running 'install_jq' (when jq already exists - install will be skipped)"
431+
rc=${RETURN_CODE_SUCCESS}
432+
install_jq >/dev/null 2>&1 || rc=$?
433+
assert_pass "${rc}"
434+
printf "%s\n\n" "✅ PASS"
435+
436+
# - Test installing exact version to /tmp even if jq already detected on $PATH
437+
printf "%s\n" "Running 'install_jq 1.8.1 /tmp false'"
438+
rc=${RETURN_CODE_SUCCESS}
439+
install_jq "1.8.1" "/tmp" "false" >/dev/null 2>&1 || rc=$?
440+
assert_pass "${rc}"
441+
printf "%s\n\n" "✅ PASS"
442+
fi
443+
226444
# -----------------------------------
227445
echo "✅ All tests passed!"
228446
}

0 commit comments

Comments
 (0)