generated from nhcarrigan/template
feat: add multi-lang support and cohort scripts (#1)
CI / dependency-pin-check-typescript (push) Successful in 4s
CI / dependency-pin-check-python (push) Successful in 3s
CI / typescript (push) Successful in 9m38s
CI / python (push) Successful in 9m23s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m6s
CI / dependency-pin-check-typescript (push) Successful in 4s
CI / dependency-pin-check-python (push) Successful in 3s
CI / typescript (push) Successful in 9m38s
CI / python (push) Successful in 9m23s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m6s
### Explanation _No response_ ### Issue _No response_ ### Attestations - [ ] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/) - [ ] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/). - [ ] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/). ### Dependencies - [ ] I have pinned the dependencies to a specific patch version. ### Style - [ ] I have run the linter and resolved any errors. - [ ] My pull request uses an appropriate title, matching the conventional commit standards. - [ ] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request. ### Tests - [ ] My contribution adds new code, and I have added tests to cover it. - [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes. - [ ] All new and existing tests pass locally with my changes. - [ ] Code coverage remains at or above the configured threshold. ### Documentation _No response_ ### Versioning _No response_ Co-authored-by: Hikari <hikari@nhcarrigan.com> Reviewed-on: #1 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors and formatting
|
||||
PINK='\033[38;5;213m'
|
||||
BLUE='\033[38;5;117m'
|
||||
GREEN='\033[38;5;156m'
|
||||
YELLOW='\033[38;5;229m'
|
||||
CYAN='\033[38;5;123m'
|
||||
WHITE='\033[1;37m'
|
||||
DIM='\033[2m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
|
||||
# Box drawing characters
|
||||
TOP_LEFT='╭'
|
||||
TOP_RIGHT='╮'
|
||||
BOTTOM_LEFT='╰'
|
||||
BOTTOM_RIGHT='╯'
|
||||
HORIZONTAL='─'
|
||||
VERTICAL='│'
|
||||
ARROW='❯'
|
||||
SPARKLE='✨'
|
||||
STAR='★'
|
||||
|
||||
# Clear screen and show header
|
||||
clear
|
||||
echo -e "${PINK}${BOLD} ${TOP_LEFT}────────────────────────────────────${TOP_RIGHT}"
|
||||
echo -e " ${VERTICAL} ${SPARKLE} ${WHITE}Ephemere Script Runner${PINK} ${SPARKLE} ${VERTICAL}"
|
||||
echo -e " ${BOTTOM_LEFT}────────────────────────────────────${BOTTOM_RIGHT}${RESET}"
|
||||
|
||||
# Function to display a menu and get selection
|
||||
select_option() {
|
||||
local prompt="$1"
|
||||
shift
|
||||
local options=("$@")
|
||||
local selected=0
|
||||
local key
|
||||
|
||||
# Hide cursor
|
||||
tput civis
|
||||
|
||||
# Trap to restore cursor on exit
|
||||
trap 'tput cnorm' EXIT
|
||||
|
||||
while true; do
|
||||
# Clear previous menu (move up and clear lines)
|
||||
if [ -n "$menu_drawn" ]; then
|
||||
for ((i=0; i<=${#options[@]}+1; i++)); do
|
||||
tput cuu1
|
||||
tput el
|
||||
done
|
||||
fi
|
||||
menu_drawn=1
|
||||
|
||||
# Print prompt
|
||||
echo -e "${CYAN}${BOLD} $prompt${RESET}"
|
||||
echo ""
|
||||
|
||||
# Print options
|
||||
for i in "${!options[@]}"; do
|
||||
if [ $i -eq $selected ]; then
|
||||
echo -e " ${PINK}${BOLD}$ARROW ${WHITE}${options[$i]}${RESET}"
|
||||
else
|
||||
echo -e " ${DIM}${options[$i]}${RESET}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Read a single keypress
|
||||
read -rsn1 key
|
||||
|
||||
# Handle arrow keys (they come as escape sequences)
|
||||
if [[ $key == $'\x1b' ]]; then
|
||||
read -rsn2 key
|
||||
case $key in
|
||||
'[A') # Up arrow
|
||||
((selected--))
|
||||
[ $selected -lt 0 ] && selected=$((${#options[@]}-1))
|
||||
;;
|
||||
'[B') # Down arrow
|
||||
((selected++))
|
||||
[ $selected -ge ${#options[@]} ] && selected=0
|
||||
;;
|
||||
esac
|
||||
elif [[ $key == "" ]]; then
|
||||
# Enter pressed
|
||||
tput cnorm # Show cursor
|
||||
unset menu_drawn
|
||||
return $selected
|
||||
elif [[ $key == "q" || $key == "Q" ]]; then
|
||||
tput cnorm
|
||||
echo -e "\n${YELLOW} Bye bye! $SPARKLE${RESET}\n"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Step 1: Select Language
|
||||
echo ""
|
||||
languages=("TypeScript" "Python")
|
||||
select_option "Select a language:" "${languages[@]}"
|
||||
lang_index=$?
|
||||
language="${languages[$lang_index]}"
|
||||
|
||||
echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$language${RESET}\n"
|
||||
|
||||
# Step 2: Get categories based on language
|
||||
if [ "$language" == "TypeScript" ]; then
|
||||
script_dir="typescript/src"
|
||||
runner="pnpm tsx"
|
||||
# Get subdirectories as categories (excluding utils and interfaces)
|
||||
mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d ! -name 'utils' ! -name 'interfaces' -exec basename {} \; | sort)
|
||||
else
|
||||
script_dir="python"
|
||||
runner="uv run python"
|
||||
# Get subdirectories as categories (excluding __pycache__ and .venv)
|
||||
mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d ! -name '__pycache__' ! -name '.venv' ! -name '*.egg-info' -exec basename {} \; | sort)
|
||||
# Add "Root Scripts" option for Python files in root
|
||||
if ls "$script_dir"/*.py &>/dev/null 2>&1; then
|
||||
categories=("Root Scripts" "${categories[@]}")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ${#categories[@]} -eq 0 ]; then
|
||||
echo -e " ${YELLOW}No script categories found!${RESET}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
select_option "Select a category:" "${categories[@]}"
|
||||
cat_index=$?
|
||||
category="${categories[$cat_index]}"
|
||||
|
||||
echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$category${RESET}\n"
|
||||
|
||||
# Step 3: Get scripts in category
|
||||
if [ "$category" == "Root Scripts" ]; then
|
||||
search_dir="$script_dir"
|
||||
mapfile -t scripts < <(find "$search_dir" -maxdepth 1 -name "*.py" -exec basename {} \; | sort)
|
||||
elif [ "$language" == "TypeScript" ]; then
|
||||
search_dir="$script_dir/$category"
|
||||
mapfile -t scripts < <(find "$search_dir" -name "*.ts" -exec basename {} \; | sort)
|
||||
else
|
||||
search_dir="$script_dir/$category"
|
||||
mapfile -t scripts < <(find "$search_dir" -name "*.py" ! -name "__init__.py" -exec basename {} \; | sort)
|
||||
fi
|
||||
|
||||
if [ ${#scripts[@]} -eq 0 ]; then
|
||||
echo -e " ${YELLOW}No scripts found in this category!${RESET}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
select_option "Select a script:" "${scripts[@]}"
|
||||
script_index=$?
|
||||
script="${scripts[$script_index]}"
|
||||
|
||||
echo -e "\n ${GREEN}$STAR Selected: ${WHITE}$script${RESET}\n"
|
||||
|
||||
# Build the full script path
|
||||
if [ "$category" == "Root Scripts" ]; then
|
||||
script_path="$script"
|
||||
elif [ "$language" == "TypeScript" ]; then
|
||||
script_path="src/$category/$script"
|
||||
else
|
||||
script_path="$category/$script"
|
||||
fi
|
||||
|
||||
# Show what we're about to run
|
||||
echo -e "${BLUE}${BOLD} ${TOP_LEFT}───────────────────────${TOP_RIGHT}"
|
||||
echo -e " ${VERTICAL} ${WHITE}Running script...${BLUE} ${VERTICAL}"
|
||||
echo -e " ${BOTTOM_LEFT}───────────────────────${BOTTOM_RIGHT}${RESET}"
|
||||
echo ""
|
||||
echo -e " ${DIM}Language:${RESET} $language"
|
||||
echo -e " ${DIM}Category:${RESET} $category"
|
||||
echo -e " ${DIM}Script:${RESET} $script"
|
||||
echo ""
|
||||
|
||||
# Run the script with 1Password env injection
|
||||
if [ "$language" == "TypeScript" ]; then
|
||||
cd typescript
|
||||
echo -e " ${DIM}$ op run --env-file=../prod.env -- $runner $script_path${RESET}\n"
|
||||
op run --env-file=../prod.env --no-masking -- $runner "$script_path"
|
||||
else
|
||||
cd python
|
||||
echo -e " ${DIM}$ op run --env-file=../prod.env -- $runner $script_path${RESET}\n"
|
||||
op run --env-file=../prod.env --no-masking -- $runner "$script_path"
|
||||
fi
|
||||
|
||||
exit_code=$?
|
||||
|
||||
echo ""
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
echo -e " ${GREEN}${BOLD}$SPARKLE Script completed successfully! $SPARKLE${RESET}\n"
|
||||
else
|
||||
echo -e " ${YELLOW}${BOLD}Script exited with code $exit_code${RESET}\n"
|
||||
fi
|
||||
Reference in New Issue
Block a user