Skip to content

Commit 535dc9f

Browse files
jlecclaude
andcommitted
chore(scripts): apply shfmt and fix shellcheck warnings in scripts/bash
Fix the three SC2155 warnings by declaring and assigning separately, so command substitution failures are no longer masked. Add "# shellcheck source=/dev/null" above each "source common.sh" to clear SC1091. Format all six scripts with shfmt, with switch_case_indent enabled in .editorconfig so existing case indentation is preserved. Beyond the three SC2155 splits, the scripts are unchanged: minified shfmt output of before and after differs only in those lines. Refs #4805 Assisted-by: Claude Code (model: Claude Sonnet 5.5, autonomous) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01THgNknAotcXL5t4tdAmkWB Signed-off-by: Justin Lecher <justin@jlec.de>
1 parent d2ddd91 commit 535dc9f

7 files changed

Lines changed: 126 additions & 50 deletions

File tree

‎.editorconfig‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ trim_trailing_whitespace = false
2020

2121
[*.{sh,bash}]
2222
indent_size = 4
23+
switch_case_indent = true
2324

2425
[*.{ps1,psm1,psd1}]
2526
indent_size = 4

‎scripts/bash/check-prerequisites.sh‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ while [[ $# -gt 0 ]]; do
5656
fi
5757
TEMPLATE_NAME="$1"
5858
;;
59-
--help|-h)
60-
cat << 'EOF'
59+
--help | -h)
60+
cat <<'EOF'
6161
Usage: check-prerequisites.sh [OPTIONS]
6262
6363
Consolidated prerequisite checking for Spec-Driven Development workflow.
@@ -94,15 +94,22 @@ done
9494

9595
# Source common functions
9696
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
97+
# shellcheck source=/dev/null
9798
source "$SCRIPT_DIR/common.sh"
9899

99100
# Get feature paths.
100101
# In --paths-only mode this is pure resolution, so pass --no-persist to opt out
101102
# of the feature.json write side effect (issue #3025).
102103
if $PATHS_ONLY; then
103-
_paths_output=$(get_feature_paths --no-persist) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
104+
_paths_output=$(get_feature_paths --no-persist) || {
105+
echo "ERROR: Failed to resolve feature paths" >&2
106+
exit 1
107+
}
104108
else
105-
_paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
109+
_paths_output=$(get_feature_paths) || {
110+
echo "ERROR: Failed to resolve feature paths" >&2
111+
exit 1
112+
}
106113
fi
107114
eval "$_paths_output"
108115
unset _paths_output
@@ -183,7 +190,12 @@ fi
183190

184191
TEMPLATE_CONTENT=""
185192
if [[ -n "$TEMPLATE_NAME" ]]; then
186-
if TEMPLATE_CONTENT=$(resolve_template_content "$TEMPLATE_NAME" "$REPO_ROOT"; status=$?; printf x; exit "$status"); then
193+
if TEMPLATE_CONTENT=$(
194+
resolve_template_content "$TEMPLATE_NAME" "$REPO_ROOT"
195+
status=$?
196+
printf x
197+
exit "$status"
198+
); then
187199
TEMPLATE_CONTENT="${TEMPLATE_CONTENT%x}"
188200
else
189201
echo "ERROR: Could not resolve required $TEMPLATE_NAME from the template override stack for $REPO_ROOT" >&2

‎scripts/bash/common.sh‎

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ get_repo_root() {
6868
fi
6969

7070
# Final fallback to script location
71-
local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
71+
local script_dir
72+
script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7273
(cd "$script_dir/../../.." && pwd)
7374
}
7475

@@ -95,7 +96,10 @@ get_current_branch() {
9596
read_feature_json_feature_directory() {
9697
local repo_root="$1"
9798
local fj="$repo_root/.specify/feature.json"
98-
[[ -f "$fj" ]] || { printf '%s' ''; return 0; }
99+
[[ -f "$fj" ]] || {
100+
printf '%s' ''
101+
return 0
102+
}
99103

100104
# Try parsers in order (jq -> python3 -> grep/sed), falling through on
101105
# failure. Selection is by *parse success*, not mere availability: on
@@ -119,9 +123,9 @@ read_feature_json_feature_directory() {
119123
if [[ -z "$_fd" ]]; then
120124
# Last-resort single-line grep/sed fallback. The `|| true` guards against
121125
# grep returning 1 (no match) aborting under `set -e` / `pipefail`.
122-
_fd=$( { grep -E '"feature_directory"[[:space:]]*:' "$fj" 2>/dev/null || true; } \
123-
| head -n 1 \
124-
| sed -E 's/^[^:]*:[[:space:]]*"([^"]*)".*$/\1/' )
126+
_fd=$({ grep -E '"feature_directory"[[:space:]]*:' "$fj" 2>/dev/null || true; } |
127+
head -n 1 |
128+
sed -E 's/^[^:]*:[[:space:]]*"([^"]*)".*$/\1/')
125129
fi
126130

127131
printf '%s' "$_fd"
@@ -154,9 +158,9 @@ _persist_feature_json() {
154158

155159
# Write feature.json — prefer jq for safe JSON, fall back to printf
156160
if command -v jq >/dev/null 2>&1; then
157-
jq -cn --arg fd "$feature_dir_value" '{feature_directory:$fd}' > "$fj"
161+
jq -cn --arg fd "$feature_dir_value" '{feature_directory:$fd}' >"$fj"
158162
else
159-
printf '{"feature_directory":"%s"}\n' "$(json_escape "$feature_dir_value")" > "$fj"
163+
printf '{"feature_directory":"%s"}\n' "$(json_escape "$feature_dir_value")" >"$fj"
160164
fi
161165
}
162166

@@ -266,14 +270,18 @@ get_invoke_separator() {
266270
local jq_separator
267271
if jq_separator=$(jq -r '(.default_integration // .integration // "") as $k | if $k == "" then "." else (.integration_settings[$k].invoke_separator // ".") end' "$integration_json" 2>/dev/null); then
268272
case "$jq_separator" in
269-
"."|"-") separator="$jq_separator"; parsed=1 ;;
273+
"." | "-")
274+
separator="$jq_separator"
275+
parsed=1
276+
;;
270277
esac
271278
fi
272279
fi
273280

274281
if [[ "$parsed" -eq 0 ]] && command -v python3 >/dev/null 2>&1; then
275282
local py_separator
276-
if py_separator=$(python3 - "$integration_json" <<'PY' 2>/dev/null
283+
if py_separator=$(
284+
python3 - "$integration_json" <<'PY' 2>/dev/null
277285
import json
278286
import sys
279287
@@ -291,9 +299,12 @@ try:
291299
except Exception:
292300
sys.exit(1)
293301
PY
294-
); then
302+
); then
295303
case "$py_separator" in
296-
"."|"-") separator="$py_separator"; parsed=1 ;;
304+
"." | "-")
305+
separator="$py_separator"
306+
parsed=1
307+
;;
297308
esac
298309
fi
299310
fi
@@ -344,7 +355,7 @@ PY
344355
}
345356
' "$integration_json" 2>/dev/null)
346357
case "$awk_separator" in
347-
"."|"-") separator="$awk_separator" ;;
358+
"." | "-") separator="$awk_separator" ;;
348359
esac
349360
fi
350361
fi
@@ -391,10 +402,10 @@ json_escape() {
391402
# so multi-byte UTF-8 sequences (first byte >= 0xC0) pass through intact.
392403
local LC_ALL=C
393404
local i char code
394-
for (( i=0; i<${#s}; i++ )); do
405+
for ((i = 0; i < ${#s}; i++)); do
395406
char="${s:$i:1}"
396407
printf -v code '%d' "'$char" 2>/dev/null || code=256
397-
if (( code >= 1 && code <= 31 )); then
408+
if ((code >= 1 && code <= 31)); then
398409
printf '\\u%04x' "$code"
399410
else
400411
printf '%s' "$char"
@@ -519,7 +530,7 @@ resolve_template() {
519530
local repo_root="$2"
520531
local base="$repo_root/.specify/templates"
521532

522-
case "$template_name" in ""|*[!a-z0-9-]*) return 1 ;; esac
533+
case "$template_name" in "" | *[!a-z0-9-]*) return 1 ;; esac
523534

524535
# Priority 1: Project overrides
525536
local override="$base/overrides/${template_name}.md"
@@ -566,7 +577,7 @@ except Exception:
566577
[ -f "$candidate" ] && echo "$candidate" && return 0
567578
candidate="$presets_dir/$preset_id/${template_name}.md"
568579
[ -f "$candidate" ] && echo "$candidate" && return 0
569-
done <<< "$sorted_presets"
580+
done <<<"$sorted_presets"
570581
fi
571582
# python3 succeeded but registry has no presets — nothing to search
572583
else
@@ -604,7 +615,7 @@ except Exception:
604615
local candidate="$ext/templates/${template_name}.md"
605616
[ -f "$candidate" ] || candidate="$ext/${template_name}.md"
606617
[ -f "$candidate" ] && echo "$candidate" && return 0
607-
done <<< "$sorted_extensions"
618+
done <<<"$sorted_extensions"
608619
fi
609620

610621
# Priority 4: Core templates
@@ -628,7 +639,7 @@ resolve_template_content() {
628639
local repo_root="$2"
629640
local base="$repo_root/.specify/templates"
630641

631-
case "$template_name" in ""|*[!a-z0-9-]*) return 1 ;; esac
642+
case "$template_name" in "" | *[!a-z0-9-]*) return 1 ;; esac
632643

633644
# Collect all layers (highest priority first)
634645
local -a layer_paths=()
@@ -776,7 +787,7 @@ except Exception as exc:
776787
fi
777788
if [ -n "$result" ]; then
778789
local declaration
779-
IFS=$'\t' read -r declaration strategy manifest_file <<< "$result"
790+
IFS=$'\t' read -r declaration strategy manifest_file <<<"$result"
780791
[ "$declaration" = "found" ] && manifest_declared=true
781792
strategy=$(printf '%s' "$strategy" | tr '[:upper:]' '[:lower:]')
782793
fi
@@ -786,7 +797,7 @@ except Exception as exc:
786797
local candidate=""
787798
if [ -n "$manifest_file" ]; then
788799
case "$manifest_file" in
789-
/*|*../*) manifest_file="" ;;
800+
/* | *../*) manifest_file="" ;;
790801
esac
791802
fi
792803
if [ -n "$manifest_file" ]; then
@@ -809,7 +820,7 @@ except Exception as exc:
809820
break
810821
fi
811822
fi
812-
done <<< "$sorted_presets"
823+
done <<<"$sorted_presets"
813824
fi
814825
fi
815826

@@ -831,7 +842,7 @@ except Exception as exc:
831842
effective_base_found=true
832843
break
833844
fi
834-
done <<< "$sorted_extensions"
845+
done <<<"$sorted_extensions"
835846
fi
836847

837848
# Priority 4: Core templates (always "replace")
@@ -872,7 +883,7 @@ except Exception as exc:
872883
# to find the nearest replace layer. Only compose layers above that base.
873884
local base_idx=-1
874885
local i
875-
for (( i=0; i<count; i++ )); do
886+
for ((i = 0; i < count; i++)); do
876887
if [ "${layer_strategies[$i]}" = "replace" ]; then
877888
base_idx=$i
878889
break
@@ -886,18 +897,28 @@ except Exception as exc:
886897

887898
# Read the base content; compose layers above the base (higher priority)
888899
local content
889-
if ! content=$(cat "${layer_paths[$base_idx]}"; status=$?; printf x; exit "$status"); then
900+
if ! content=$(
901+
cat "${layer_paths[$base_idx]}"
902+
status=$?
903+
printf x
904+
exit "$status"
905+
); then
890906
echo "Error: failed to read template layer ${layer_paths[$base_idx]}" >&2
891907
return 2
892908
fi
893909
content="${content%x}"
894910

895-
for (( i=base_idx-1; i>=0; i-- )); do
911+
for ((i = base_idx - 1; i >= 0; i--)); do
896912
local path="${layer_paths[$i]}"
897913
local strat="${layer_strategies[$i]}"
898914
local layer_content
899915
# Preserve trailing newlines
900-
if ! layer_content=$(cat "$path"; status=$?; printf x; exit "$status"); then
916+
if ! layer_content=$(
917+
cat "$path"
918+
status=$?
919+
printf x
920+
exit "$status"
921+
); then
901922
echo "Error: failed to read template layer $path" >&2
902923
return 2
903924
fi
@@ -906,17 +927,26 @@ except Exception as exc:
906927
case "$strat" in
907928
replace) content="$layer_content" ;;
908929
prepend)
909-
content=$(printf '%s\n\n%s' "$layer_content" "$content"; printf x)
930+
content=$(
931+
printf '%s\n\n%s' "$layer_content" "$content"
932+
printf x
933+
)
910934
content="${content%x}"
911935
;;
912936
append)
913-
content=$(printf '%s\n\n%s' "$content" "$layer_content"; printf x)
937+
content=$(
938+
printf '%s\n\n%s' "$content" "$layer_content"
939+
printf x
940+
)
914941
content="${content%x}"
915942
;;
916943
wrap)
917944
case "$layer_content" in
918945
*'{CORE_TEMPLATE}'*) ;;
919-
*) echo "Error: wrap strategy missing {CORE_TEMPLATE} placeholder" >&2; return 2 ;;
946+
*)
947+
echo "Error: wrap strategy missing {CORE_TEMPLATE} placeholder" >&2
948+
return 2
949+
;;
920950
esac
921951
# Consume the wrapper left to right instead of rewriting it in
922952
# place. Rewriting re-scanned the string just modified, so base
@@ -933,7 +963,10 @@ except Exception as exc:
933963
done
934964
content="${wrapped}${rest}"
935965
;;
936-
*) echo "Error: unknown strategy '$strat'" >&2; return 2 ;;
966+
*)
967+
echo "Error: unknown strategy '$strat'" >&2
968+
return 2
969+
;;
937970
esac
938971
done
939972

‎scripts/bash/create-new-feature.sh‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ while [ $i -le $# ]; do
5656
--timestamp)
5757
USE_TIMESTAMP=true
5858
;;
59-
--help|-h)
59+
--help | -h)
6060
echo "Usage: $0 [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
6161
echo ""
6262
echo "Options:"
@@ -166,7 +166,7 @@ fit_branch_name() {
166166
local branch_name="${feature_num}-${branch_suffix}"
167167

168168
if [ ${#branch_name} -gt $MAX_BRANCH_LENGTH ]; then
169-
local prefix_length=$(( ${#feature_num} + 1 ))
169+
local prefix_length=$((${#feature_num} + 1))
170170
local max_suffix_length=$((MAX_BRANCH_LENGTH - prefix_length))
171171
local truncated_suffix
172172
truncated_suffix=$(printf '%s' "$branch_suffix" | cut -c "1-$max_suffix_length" | sed 's/-$//')
@@ -191,6 +191,7 @@ shell_quote() {
191191

192192
# Resolve repository root using common.sh functions which prioritize .specify
193193
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
194+
# shellcheck source=/dev/null
194195
source "$SCRIPT_DIR/common.sh"
195196

196197
REPO_ROOT=$(get_repo_root) || exit 1
@@ -214,7 +215,8 @@ generate_branch_name() {
214215
# acronym probe below uses ASCII word boundaries like the Python twin's
215216
# (?<![0-9A-Za-z_]) lookarounds.
216217
local -x LC_ALL=C
217-
local clean_name=$(printf '%s' "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
218+
local clean_name
219+
clean_name=$(printf '%s' "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
218220

219221
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
220222
local meaningful_words=()
@@ -251,7 +253,8 @@ generate_branch_name() {
251253
echo "$result"
252254
else
253255
# Fallback to original logic if no meaningful words found
254-
local cleaned=$(clean_branch_name "$description")
256+
local cleaned
257+
cleaned=$(clean_branch_name "$description")
255258
echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
256259
fi
257260
}
@@ -361,7 +364,12 @@ if [ "$DRY_RUN" != true ]; then
361364
SPEC_TEMPLATE_CONTENT=""
362365
if [ ! -f "$SPEC_FILE" ]; then
363366
NEEDS_SPEC=true
364-
if SPEC_TEMPLATE_CONTENT=$(resolve_template_content "spec-template" "$REPO_ROOT"; status=$?; printf x; exit "$status"); then
367+
if SPEC_TEMPLATE_CONTENT=$(
368+
resolve_template_content "spec-template" "$REPO_ROOT"
369+
status=$?
370+
printf x
371+
exit "$status"
372+
); then
365373
SPEC_TEMPLATE_CONTENT="${SPEC_TEMPLATE_CONTENT%x}"
366374
SPEC_TEMPLATE_FOUND=true
367375
else
@@ -376,7 +384,7 @@ if [ "$DRY_RUN" != true ]; then
376384

377385
if [ "$NEEDS_SPEC" = true ]; then
378386
if [ "$SPEC_TEMPLATE_FOUND" = true ]; then
379-
printf '%s' "$SPEC_TEMPLATE_CONTENT" > "$SPEC_FILE"
387+
printf '%s' "$SPEC_TEMPLATE_CONTENT" >"$SPEC_FILE"
380388
else
381389
echo "Warning: Spec template not found; created empty spec file" >&2
382390
touch "$SPEC_FILE"

0 commit comments

Comments
 (0)