Files
ephemere/run.sh
T
hikari ec58c9c843
CI / dependency-pin-check-typescript (push) Successful in 5s
CI / dependency-pin-check-python (push) Successful in 4s
CI / python (push) Successful in 9m28s
CI / typescript (push) Successful in 9m42s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m39s
feat: reorganise bash scripts and add comprehensive documentation (#6)
## Summary

This PR completes the bash script restructuring and adds comprehensive documentation across all script categories.

### Bash Restructuring

- Moved cohort shell scripts (`remove_github_members.sh`, `update_github_teams.sh`) from `python/cohort/` into a new `bash/cohort/` directory
- Moved existing bash utilities (`add-keys-to-git.sh`, `fix-yubikey-perms.sh`, `list-yubikey-ssh-keys.sh`) into a new `bash/yubikey/` subdirectory
- Updated `run.sh` to support **Bash** as a third language option alongside TypeScript and Python
  - Bash scripts are run directly (no 1Password secret injection needed)
  - Category discovery and script listing works the same as for TS/Python
  - Removed dead "Root Scripts" logic that was no longer needed

### Documentation

Added `README.md` files for all script categories that were missing them:

- `bash/cohort/README.md` — cohort GitHub team management scripts
- `bash/yubikey/README.md` — YubiKey SSH key and permission utilities
- `typescript/src/crowdin/README.md` — Crowdin translation management scripts
- `typescript/src/discord/README.md` — Discord bot utility scripts
- `typescript/src/discourse/README.md` — Discourse forum management scripts
- `typescript/src/gitea/README.md` — Gitea bulk repository operation scripts
- `typescript/src/github/README.md` — GitHub API interaction scripts
- `typescript/src/music/README.md` — Music file metadata tools
- `typescript/src/s3/README.md` — S3-compatible object storage scripts
- `typescript/src/security/README.md` — Security analysis and reporting scripts
- `python/cohort/README.md` — Updated to remove moved shell scripts, fix usage commands

Also updated project-level docs:

- **`README.md`** — Corrected project structure, fixed running instructions (removed references to non-existent `make run-ts`/`make run-py` targets), added Bash prerequisites
- **`CLAUDE.md`** — Updated project overview, structure, development standards, and script-adding guides to reflect the current state of the project

 This PR was created with help from Hikari~ 🌸

Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Reviewed-on: #6
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-02-23 20:18:41 -08:00

199 lines
6.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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" "Bash")
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)
elif [ "$language" == "Python" ]; then
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)
else
script_dir="bash"
runner="bash"
# Get subdirectories as categories
mapfile -t categories < <(find "$script_dir" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
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 [ "$language" == "TypeScript" ]; then
search_dir="$script_dir/$category"
mapfile -t scripts < <(find "$search_dir" -name "*.ts" -exec basename {} \; | sort)
elif [ "$language" == "Bash" ]; then
search_dir="$script_dir/$category"
mapfile -t scripts < <(find "$search_dir" -name "*.sh" -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 [ "$language" == "Bash" ]; then
script_path="bash/$category/$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"
elif [ "$language" == "Bash" ]; then
echo -e " ${DIM}$ $runner $script_path${RESET}\n"
$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