|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# Consolidated prerequisite checking script |
| 4 | +# |
| 5 | +# This script provides unified prerequisite checking for Spec-Driven Development workflow. |
| 6 | +# It replaces the functionality previously spread across multiple scripts. |
| 7 | +# |
| 8 | +# Usage: ./check-prerequisites.sh [OPTIONS] |
| 9 | +# |
| 10 | +# OPTIONS: |
| 11 | +# --json Output in JSON format |
| 12 | +# --require-tasks Require tasks.md to exist (for implementation phase) |
| 13 | +# --include-tasks Include tasks.md in AVAILABLE_DOCS list |
| 14 | +# --paths-only Only output path variables (no validation) |
| 15 | +# --help, -h Show help message |
| 16 | +# |
| 17 | +# OUTPUTS: |
| 18 | +# JSON mode: {"FEATURE_DIR":"...", "AVAILABLE_DOCS":["..."]} |
| 19 | +# Text mode: FEATURE_DIR:... \n AVAILABLE_DOCS: \n ✓/✗ file.md |
| 20 | +# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... etc. |
| 21 | + |
| 22 | +set -e |
| 23 | + |
| 24 | +# Parse command line arguments |
| 25 | +JSON_MODE=false |
| 26 | +REQUIRE_TASKS=false |
| 27 | +INCLUDE_TASKS=false |
| 28 | +PATHS_ONLY=false |
| 29 | + |
| 30 | +for arg in "$@"; do |
| 31 | + case "$arg" in |
| 32 | + --json) |
| 33 | + JSON_MODE=true |
| 34 | + ;; |
| 35 | + --require-tasks) |
| 36 | + REQUIRE_TASKS=true |
| 37 | + ;; |
| 38 | + --include-tasks) |
| 39 | + INCLUDE_TASKS=true |
| 40 | + ;; |
| 41 | + --paths-only) |
| 42 | + PATHS_ONLY=true |
| 43 | + ;; |
| 44 | + --help|-h) |
| 45 | + cat << 'EOF' |
| 46 | +Usage: check-prerequisites.sh [OPTIONS] |
| 47 | +
|
| 48 | +Consolidated prerequisite checking for Spec-Driven Development workflow. |
| 49 | +
|
| 50 | +OPTIONS: |
| 51 | + --json Output in JSON format |
| 52 | + --require-tasks Require tasks.md to exist (for implementation phase) |
| 53 | + --include-tasks Include tasks.md in AVAILABLE_DOCS list |
| 54 | + --paths-only Only output path variables (no prerequisite validation) |
| 55 | + --help, -h Show this help message |
| 56 | +
|
| 57 | +EXAMPLES: |
| 58 | + # Check task prerequisites (plan.md required) |
| 59 | + ./check-prerequisites.sh --json |
| 60 | +
|
| 61 | + # Check implementation prerequisites (plan.md + tasks.md required) |
| 62 | + ./check-prerequisites.sh --json --require-tasks --include-tasks |
| 63 | +
|
| 64 | + # Get feature paths only (no validation) |
| 65 | + ./check-prerequisites.sh --paths-only |
| 66 | +
|
| 67 | +EOF |
| 68 | + exit 0 |
| 69 | + ;; |
| 70 | + *) |
| 71 | + echo "ERROR: Unknown option '$arg'. Use --help for usage information." >&2 |
| 72 | + exit 1 |
| 73 | + ;; |
| 74 | + esac |
| 75 | +done |
| 76 | + |
| 77 | +# Source common functions |
| 78 | +SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 79 | +source "$SCRIPT_DIR/common.sh" |
| 80 | + |
| 81 | +# Get feature paths and validate branch |
| 82 | +_paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; } |
| 83 | +eval "$_paths_output" |
| 84 | +unset _paths_output |
| 85 | +check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 |
| 86 | + |
| 87 | +# If paths-only mode, output paths and exit (support JSON + paths-only combined) |
| 88 | +if $PATHS_ONLY; then |
| 89 | + if $JSON_MODE; then |
| 90 | + # Minimal JSON paths payload (no validation performed) |
| 91 | + if has_jq; then |
| 92 | + jq -cn \ |
| 93 | + --arg repo_root "$REPO_ROOT" \ |
| 94 | + --arg branch "$CURRENT_BRANCH" \ |
| 95 | + --arg feature_dir "$FEATURE_DIR" \ |
| 96 | + --arg feature_spec "$FEATURE_SPEC" \ |
| 97 | + --arg impl_plan "$IMPL_PLAN" \ |
| 98 | + --arg tasks "$TASKS" \ |
| 99 | + '{REPO_ROOT:$repo_root,BRANCH:$branch,FEATURE_DIR:$feature_dir,FEATURE_SPEC:$feature_spec,IMPL_PLAN:$impl_plan,TASKS:$tasks}' |
| 100 | + else |
| 101 | + printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \ |
| 102 | + "$(json_escape "$REPO_ROOT")" "$(json_escape "$CURRENT_BRANCH")" "$(json_escape "$FEATURE_DIR")" "$(json_escape "$FEATURE_SPEC")" "$(json_escape "$IMPL_PLAN")" "$(json_escape "$TASKS")" |
| 103 | + fi |
| 104 | + else |
| 105 | + echo "REPO_ROOT: $REPO_ROOT" |
| 106 | + echo "BRANCH: $CURRENT_BRANCH" |
| 107 | + echo "FEATURE_DIR: $FEATURE_DIR" |
| 108 | + echo "FEATURE_SPEC: $FEATURE_SPEC" |
| 109 | + echo "IMPL_PLAN: $IMPL_PLAN" |
| 110 | + echo "TASKS: $TASKS" |
| 111 | + fi |
| 112 | + exit 0 |
| 113 | +fi |
| 114 | + |
| 115 | +# Validate required directories and files |
| 116 | +if [[ ! -d "$FEATURE_DIR" ]]; then |
| 117 | + echo "ERROR: Feature directory not found: $FEATURE_DIR" >&2 |
| 118 | + echo "Run /speckit.specify first to create the feature structure." >&2 |
| 119 | + exit 1 |
| 120 | +fi |
| 121 | + |
| 122 | +if [[ ! -f "$IMPL_PLAN" ]]; then |
| 123 | + echo "ERROR: plan.md not found in $FEATURE_DIR" >&2 |
| 124 | + echo "Run /speckit.plan first to create the implementation plan." >&2 |
| 125 | + exit 1 |
| 126 | +fi |
| 127 | + |
| 128 | +# Check for tasks.md if required |
| 129 | +if $REQUIRE_TASKS && [[ ! -f "$TASKS" ]]; then |
| 130 | + echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2 |
| 131 | + echo "Run /speckit.tasks first to create the task list." >&2 |
| 132 | + exit 1 |
| 133 | +fi |
| 134 | + |
| 135 | +# Build list of available documents |
| 136 | +docs=() |
| 137 | + |
| 138 | +# Always check these optional docs |
| 139 | +[[ -f "$RESEARCH" ]] && docs+=("research.md") |
| 140 | +[[ -f "$DATA_MODEL" ]] && docs+=("data-model.md") |
| 141 | + |
| 142 | +# Check contracts directory (only if it exists and has files) |
| 143 | +if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then |
| 144 | + docs+=("contracts/") |
| 145 | +fi |
| 146 | + |
| 147 | +[[ -f "$QUICKSTART" ]] && docs+=("quickstart.md") |
| 148 | + |
| 149 | +# Include tasks.md if requested and it exists |
| 150 | +if $INCLUDE_TASKS && [[ -f "$TASKS" ]]; then |
| 151 | + docs+=("tasks.md") |
| 152 | +fi |
| 153 | + |
| 154 | +# Output results |
| 155 | +if $JSON_MODE; then |
| 156 | + # Build JSON array of documents |
| 157 | + if has_jq; then |
| 158 | + if [[ ${#docs[@]} -eq 0 ]]; then |
| 159 | + json_docs="[]" |
| 160 | + else |
| 161 | + json_docs=$(printf '%s\n' "${docs[@]}" | jq -R . | jq -s .) |
| 162 | + fi |
| 163 | + jq -cn \ |
| 164 | + --arg feature_dir "$FEATURE_DIR" \ |
| 165 | + --argjson docs "$json_docs" \ |
| 166 | + '{FEATURE_DIR:$feature_dir,AVAILABLE_DOCS:$docs}' |
| 167 | + else |
| 168 | + if [[ ${#docs[@]} -eq 0 ]]; then |
| 169 | + json_docs="[]" |
| 170 | + else |
| 171 | + json_docs=$(for d in "${docs[@]}"; do printf '"%s",' "$(json_escape "$d")"; done) |
| 172 | + json_docs="[${json_docs%,}]" |
| 173 | + fi |
| 174 | + printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$(json_escape "$FEATURE_DIR")" "$json_docs" |
| 175 | + fi |
| 176 | +else |
| 177 | + # Text output |
| 178 | + echo "FEATURE_DIR:$FEATURE_DIR" |
| 179 | + echo "AVAILABLE_DOCS:" |
| 180 | + |
| 181 | + # Show status of each potential document |
| 182 | + check_file "$RESEARCH" "research.md" |
| 183 | + check_file "$DATA_MODEL" "data-model.md" |
| 184 | + check_dir "$CONTRACTS_DIR" "contracts/" |
| 185 | + check_file "$QUICKSTART" "quickstart.md" |
| 186 | + |
| 187 | + if $INCLUDE_TASKS; then |
| 188 | + check_file "$TASKS" "tasks.md" |
| 189 | + fi |
| 190 | +fi |
0 commit comments