#!/usr/bin/env bash # Oodikone CLI tool (revision 2.0) # Bash template provided by: # https://betterdev.blog/minimal-safe-bash-script-template/ set -Eueo pipefail trap cleanup SIGINT SIGTERM ERR EXIT # Constants # Resolve relative to the script's own location (not the caller's cwd), so # `ok.sh` behaves the same whether it's run as `./ok.sh` from the repo or # invoked with an absolute/symlinked path from anywhere (e.g. the `ok` # shell function installed via `./ok.sh install`). SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR" && git rev-parse --show-toplevel)" cd "$PROJECT_ROOT" # Include scripts from other sources source "$PROJECT_ROOT"/scripts/functions_for_setup.sh usage() { cat << EOF # remove the space between << and EOF, this is due to web plugin issue Usage: $(basename "${BASH_SOURCE[0]}") [command] Run without a command to open the interactive menu. Available commands: up, u, r, real Start Oodikone with real data rs, rl Restart Oodikone with real data (down, then up) anon, a Start Oodikone with anonymous data down, d Stop Oodikone logs, l Follow oodikone service logs logs:updater, lu Follow sis-updater service logs lint, li Lint the project or the path given as parameter format, fmt, f Format the project or the path given as parameter test:backend, tb Run backend unit tests test:frontend, tf Run frontend unit tests test:updater, tu Run updater (worker) unit tests test:services, ts Run backend service tests test:api, ta Run backend api tests test:component, tc Run frontend component tests tests test:e2e, te Run all e2e tests (add --ui to run in headed mode) importer, i Open a psql/pgcli shell to the importer database updater Open a psql/pgcli shell to the updater (sis) database install Add the 'ok' shell function to your shell rc file -h, --help Print this help and exit EOF exit } cleanup() { trap - SIGINT SIGTERM ERR EXIT msg "" errormsg "(╯°□°)╯︵ ┻━┻" } setup_colors() { if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then NOFORMAT='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' else NOFORMAT='' RED='' GREEN='' ORANGE='' BLUE='' fi } die() { local msg=$1 local code=${2-1} # default exit status 1 msg "$msg" exit "$code" } get_pgclient() { if command -v pgcli >/dev/null 2>&1; then echo "pgcli" else warningmsg "Couldn't verify pgcli installation, using psql as fallback" >&2 echo "psql" fi } show_welcome() { local cashmoneyyellow cashmoneyyellow=$(tput setaf 221) local normal normal=$(tput sgr0) if [ "$(tput cols)" -gt "76" ]; then while IFS="" read -r p || [ -n "$p" ]; do printf '%40s\n' "${cashmoneyyellow}$p${normal}" done < "$PROJECT_ROOT"/scripts/assets/logo.txt fi msg "Welcome to Oodikone CLI!" msg "" } main_menu_opts() { msg "1) Start Oodikone 2) Databases 3) Data refresh 4) Setup q) Quit\n" } database_menu_opts() { msg "\nView local databases ($datasource data)" msg "suffix: $dbsuffix" msg "1) Oodikone" msg "2) Importer" msg "3) Kone" msg "4) Toggle data source (test/real)" msg "5) Go back" msg "" } database_menu() { # If a single mandatory service is down, an assumption is made that they all are. if ! docker compose ps 2>/dev/null | grep -q 'oodikone-backend'; then msg "" warningmsg "Can't access databases, oodikone is not running!\nPlease run option 1 first with preferred data source." return fi declare dbsuffix="-real" declare datasource="real" toggle_environment() { if [[ $dbsuffix = "" ]]; then dbsuffix="-real" datasource="real" else dbsuffix="" datasource="test" fi } local pgclient pgclient="$(get_pgclient)" msg "${GREEN}\nUsing $pgclient for database connections${NOFORMAT}" database_menu_opts $datasource local userinput while true; do read -r -s -n 1 -p "Please select an option: " userinput case ${userinput} in 1|o|O) msg "Oodikone-db" $pgclient -h localhost -p 12345 -U postgres -d "sis-db$dbsuffix" -w database_menu_opts ;; 2|i|I) msg "Importer-db" $pgclient -h localhost -p 12346 -U postgres -d "sis-importer-db$dbsuffix" -w database_menu_opts ;; 3|k|K) msg "Kone-db" $pgclient -h localhost -p 4321 -U postgres -d "kone-db$dbsuffix" -w database_menu_opts ;; 4|t|T) msg "Toggling environment..." database_menu_opts ;; 5|q|Q) msg "" break ;; *) true ;; esac done } main_loop() { local userinput while true; do main_menu_opts read -r -s -n 1 -p "Please select an option: " userinput case ${userinput} in 1) msg "\nTODO: todo\n";; 2) database_menu;; 3) msg "\nTODO: todo\n";; 4) msg "\nTODO: todo\n";; 5|q|Q) break 2;; *) errormsg "${RED}Invalid option:${NOFORMAT} $userinput";; esac done } # === Direct (non-interactive) commands === run_up() { infomsg "Starting Oodikone with real data..." npm run both:real "$@" } run_restart() { infomsg "Restarting Oodikone with real data..." npm run docker:down npm run both:real } run_anon() { infomsg "Starting Oodikone with anonymous data..." npm run both "$@" } run_down() { infomsg "Stopping Oodikone..." npm run docker:down "$@" } run_logs() { npm run logs "$@" } run_lint() { npm run lint -- "$@" } run_format() { npm run fmt -- "$@" } run_unit_tests() { npm run test:unit --prefix "$@" } run_component_tests() { npm run test:component --prefix services/frontend "$@" } run_service_tests() { npm run test:services --prefix services/backend "$@" } run_api_tests() { npm run test:api --prefix services/backend "$@" } run_e2e_tests() { npm run playwright -- "$@" } run_logs_updater() { docker compose --file docker-compose.yml logs sis-updater-worker sis-updater-scheduler -f } run_importer_db() { local pgclient pgclient="$(get_pgclient)" msg "Importer-db" $pgclient -h localhost -p 12346 -U postgres -d sis-importer-db-real -w } run_updater_db() { local pgclient pgclient="$(get_pgclient)" msg "Updater-db" $pgclient -h localhost -p 12345 -U postgres -d sis-db-real -w } # Add (or refresh) an `ok` shell function in the user's shell rc file, which # simply forwards all arguments to this script. This is the one-time setup # step referenced above the shell function no longer needs its own copy of # oodikone-specific logic. cmd_install() { local shell_name shell_name="$(basename "${SHELL:-bash}")" local shell_rc case "$shell_name" in zsh) shell_rc="$HOME/.zshrc" ;; *) shell_rc="$HOME/.bashrc" ;; esac local ok_path="$PROJECT_ROOT/ok.sh" local marker_start="# >>> oodikone ok.sh >>>" local marker_end="# <<< oodikone ok.sh <<<" if [ -f "$shell_rc" ] && grep -qF "$marker_start" "$shell_rc"; then warningmsg "ok.sh integration already present in $shell_rc, skipping." infomsg "To reinstall (e.g. after moving the repo), remove the block between\n'$marker_start' and '$marker_end' in $shell_rc and re-run 'ok.sh install'." return 0 fi { echo "" echo "$marker_start" echo "ok() { \"$ok_path\" \"\$@\"; }" echo "$marker_end" } >> "$shell_rc" successmsg "Added the 'ok' function to $shell_rc" infomsg "Run 'source $shell_rc' or restart your shell, then try 'ok up'." } # Main setup_colors case "${1-}" in up|u|r|real) shift run_up "$@" ;; rs|rl) shift run_restart "$@" ;; anon|a) shift run_anon "$@" ;; down|d) shift run_down "$@" ;; logs|l) shift run_logs "$@" ;; lint|li) shift run_lint "$@" ;; format|fmt|f) shift run_format "$@" ;; test:backend|tb) shift run_unit_tests services/backend "$@" ;; test:frontend|tf) shift run_unit_tests services/frontend "$@" ;; test:updater|tu) shift run_unit_tests updater/sis-updater-worker "$@" ;; test:services|ts) shift run_service_tests "$@" ;; test:api|ta) shift run_api_tests "$@" ;; test:component|tc) shift run_component_tests "$@" ;; test:e2e|te) shift run_e2e_tests "$@" ;; logs:updater|lu) shift run_logs_updater "$@" ;; importer|i) shift run_importer_db ;; updater) shift run_updater_db ;; install) shift cmd_install ;; -h|--help) usage ;; "") show_welcome get_s3_config main_loop ;; *) errormsg "Unknown command: $1" usage ;; esac