Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 124 additions & 14 deletions .devcontainer/tools/captain_utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,113 @@ set -e
set -u
set -o pipefail

# --- Flow mode infrastructure ---
FLOW_MODE=false
FLOW_QUEUE=()
# Use a temp file for FLOW_INDEX so it persists across subshells created by $()
FLOW_INDEX_FILE=$(mktemp)
echo 0 > "$FLOW_INDEX_FILE"
trap 'rm -f "$FLOW_INDEX_FILE"' EXIT

_flow_get_index() { cat "$FLOW_INDEX_FILE"; }
_flow_set_index() { echo "$1" > "$FLOW_INDEX_FILE"; }

while [[ $# -gt 0 ]]; do
case "$1" in
--flow)
FLOW_MODE=true
IFS=',' read -r -a FLOW_QUEUE <<< "$2"
Comment on lines +18 to +24
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flow queue parsing doesn’t trim whitespace around comma-separated values. A common input like --flow "1, 2,3" produces an element with a leading space (" 2"), which will fail the numeric validation later. Consider stripping spaces (e.g., remove whitespace after splitting, or set IFS=', ' with additional normalization) so flow mode is resilient to typical CLI formatting.

Suggested change
_flow_set_index() { echo "$1" > "$FLOW_INDEX_FILE"; }
while [[ $# -gt 0 ]]; do
case "$1" in
--flow)
FLOW_MODE=true
IFS=',' read -r -a FLOW_QUEUE <<< "$2"
_flow_set_index() { echo "$1" > "$FLOW_INDEX_FILE"; }
_trim_whitespace() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--flow)
FLOW_MODE=true
IFS=',' read -r -a FLOW_QUEUE <<< "$2"
for i in "${!FLOW_QUEUE[@]}"; do
FLOW_QUEUE[$i]=$(_trim_whitespace "${FLOW_QUEUE[$i]}")
done

Copilot uses AI. Check for mistakes.
shift 2
;;
Comment on lines +20 to +26
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--flow option parsing assumes a second argument exists. With set -u/set -e, running captain_utils.sh --flow (missing queue) will error via an unbound $2 and/or shift 2, instead of showing a helpful usage message. Add an explicit [[ $# -ge 2 ]] guard (and ideally validate non-empty) before reading $2 and shifting.

Copilot uses AI. Check for mistakes.
*)
echo "Unknown option: $1" >&2
Comment thread
hamzabouissi marked this conversation as resolved.
exit 1
;;
esac
done

# Wrapper for gum choose. In flow mode, consumes next queue value as 1-based index.
# In interactive mode, shows indexed options and strips index prefix from result.
flow_choose() {
local options=("$@")
if [ "$FLOW_MODE" = true ]; then
local flow_index=$(_flow_get_index)
if [ "$flow_index" -ge "${#FLOW_QUEUE[@]}" ]; then
echo "Flow complete." >&2
exit 1
fi
local idx="${FLOW_QUEUE[$flow_index]}"
_flow_set_index $((flow_index + 1))
if ! [[ "$idx" =~ ^[0-9]+$ ]] || [ "$idx" -lt 1 ] || [ "$idx" -gt "${#options[@]}" ]; then
echo "Invalid flow index '$idx'. Valid range: 1-${#options[@]} for options: ${options[*]}" >&2
exit 1
fi
local selected="${options[$((idx - 1))]}"
echo "[flow] Selected: $selected" >&2
echo "$selected"
else
local indexed_options=()
for i in "${!options[@]}"; do
indexed_options+=("$((i + 1)). ${options[$i]}")
done
local choice
choice=$(gum choose "${indexed_options[@]}")
# Strip the "N. " prefix
echo "$choice" | sed 's/^[0-9]*\. //'
fi
}

# Wrapper for gum confirm. In flow mode, consumes next queue value (y/n).
flow_confirm() {
local prompt="$1"
if [ "$FLOW_MODE" = true ]; then
local flow_index=$(_flow_get_index)
if [ "$flow_index" -ge "${#FLOW_QUEUE[@]}" ]; then
echo "Flow complete." >&2
exit 0
fi
local val="${FLOW_QUEUE[$flow_index]}"
_flow_set_index $((flow_index + 1))
echo "[flow] Confirm '$prompt': $val" >&2
if [ "$val" = "y" ] || [ "$val" = "Y" ]; then
return 0
else
return 1
fi
Comment thread
hamzabouissi marked this conversation as resolved.
else
gum confirm "$prompt"
fi
}

# Wrapper for gum pager. In flow mode, uses cat to avoid blocking.
flow_pager() {
if [ "$FLOW_MODE" = true ]; then
cat
else
gum pager
fi
}

run_prerequisite_commands(){
helm repo add argo https://argoproj.github.io/argo-helm
helm repo add glueops-platform https://helm.gpkg.io/platform
helm repo add glueops-service https://helm.gpkg.io/service
helm repo add glueops-project-template https://helm.gpkg.io/project-template
helm repo add incubating-glueops-platform https://incubating-helm.gpkg.io/platform
helm repo add incubating-glueops-service https://incubating-helm.gpkg.io/service
helm repo add incubating-glueops-project-template https://incubating-helm.gpkg.io/project-template
helm repo add projectcalico https://docs.tigera.io/calico/charts
helm repo update
if ! helm plugin list | grep -q '^diff'; then
helm plugin install https://github.com/databus23/helm-diff
fi
}

check_codespace_version_match(){
codespace_version=`yq '.versions[] | select(.name == "codespace_version") | .version' VERSIONS/glueops.yaml`
if [ "$codespace_version" != $VERSION ]; then
gum style --foreground 196 --bold "Current codespace version doesn't match with the desired: ${codespace_version}"
if ! gum confirm "Confirmation"; then
if ! flow_confirm "Confirmation"; then
return 1
fi
fi
Expand Down Expand Up @@ -60,7 +158,7 @@ handle_platform_upgrades() {
gum style --foreground 196 --bold "No Overrides.yaml detected"
overrides_file="platform.yaml"
fi
version=$(gum choose "${versions[@]}" "Back")
version=$(flow_choose "${versions[@]}" "Back") || exit 0

# Check if user wants to go back
if [ "$version" = "Back" ]; then
Expand All @@ -71,11 +169,11 @@ handle_platform_upgrades() {
helm_diff_cmd="helm diff --color upgrade \"$component\" \"$chart_name\" --version \"$version\" -f \"$target_file\" -f \"$overrides_file\" -n \"$namespace\" --allow-unreleased"

set -x
eval "$helm_diff_cmd | gum pager" # Execute the main helm diff command
eval "$helm_diff_cmd" | flow_pager # Execute the main helm diff command
gum style --bold --foreground 212 "✅ Diff complete."
Comment thread
hamzabouissi marked this conversation as resolved.
set +x

if ! gum confirm "Apply upgrade"; then
if ! flow_confirm "Apply upgrade"; then
return
fi

Expand Down Expand Up @@ -105,7 +203,7 @@ handle_argocd() {
target_file="argocd.yaml"
namespace="glueops-core"
chart_name="argo/argo-cd"
version=$(gum choose "${versions[@]}" "Back")
version=$(flow_choose "${versions[@]}" "Back") || exit 0

# Check if user wants to go back
if [ "$version" = "Back" ]; then
Expand All @@ -122,19 +220,19 @@ handle_argocd() {
else
local argocd_crd_versions=`v($(helm search repo argo/argo-cd --versions -o json | jq --arg chart_helm_version "$version" -r '.[] | select(.version == $chart_helm_version).app_version' | sed 's/^v//'))`
fi
chosen_crd_version=$(gum choose "${argocd_crd_versions[@]}" "Back")
chosen_crd_version=$(flow_choose "${argocd_crd_versions[@]}" "Back") || exit 0
pre_commands="kubectl apply -k \"https://github.com/argoproj/argo-cd/manifests/crds?ref=$chosen_crd_version\" && helm repo update"
# Check if user wants to go back
if [ "$chosen_crd_version" = "Back" ]; then
return
fi

set -x
eval "$helm_diff_cmd | gum pager" # Execute the main helm diff command
eval "$helm_diff_cmd" | flow_pager # Execute the main helm diff command
gum style --bold --foreground 212 "✅ Diff complete."
set +x

if ! gum confirm "Apply upgrade"; then
if ! flow_confirm "Apply upgrade"; then
return
fi

Expand Down Expand Up @@ -164,15 +262,26 @@ handle_argocd() {

handle_calico_upgrades() {
calico_version=`yq '.versions[] | select(.name == "calico_helm_chart_version") | .version' VERSIONS/glueops.yaml`

helm repo add projectcalico https://docs.tigera.io/calico/charts
helm repo update

set -x
helm diff --color upgrade calico projectcalico/tigera-operator --version ${calico_version} --namespace tigera-operator -f calico.yaml --allow-unreleased | flow_pager
gum style --bold --foreground 212 "✅ Diff complete."
Comment thread
hamzabouissi marked this conversation as resolved.
set +x

if ! flow_confirm "Apply calico upgrade"; then
return
fi

remove_daemonset='kubectl delete daemonset -n kube-system aws-node'
gum style --bold --foreground 196 "Removing eks daemonset"
set -x
${remove_daemonset} || true

gum style --bold --foreground 196 "Deploying calico helm chart ${calico_version}"

helm repo add projectcalico https://docs.tigera.io/calico/charts
helm repo update
helm upgrade --install calico projectcalico/tigera-operator --version ${calico_version} --namespace tigera-operator -f calico.yaml --create-namespace

set +x
Expand All @@ -195,7 +304,8 @@ handle_kubernetes_version() {


handle_aws_options() {
local aws_component=$(gum choose "calico" "eks-addons" "upgrade-eks-nodepools" "upgrade-kubernetes" "Exit")
local aws_component
aws_component=$(flow_choose "calico" "eks-addons" "upgrade-eks-nodepools" "upgrade-kubernetes" "Exit") || exit 0
# Handle exit option
if [ "$aws_component" = "Exit" ]; then
echo "Goodbye!"
Expand Down Expand Up @@ -227,7 +337,7 @@ handle_inspect_pods() {

show_production(){
while true; do
component=$(gum choose "show_diff_table" "argocd" "glueops-platform" "aws" "inspect_pods" "Exit")
component=$(flow_choose "show_diff_table" "argocd" "glueops-platform" "aws" "inspect_pods" "Exit") || exit 0

# Handle exit option
if [ "$component" = "Exit" ]; then
Expand Down Expand Up @@ -261,7 +371,7 @@ show_production(){

show_dev(){
while true; do
component=$(gum choose "argocd" "glueops-platform" "aws" "Exit")
component=$(flow_choose "argocd" "glueops-platform" "aws" "Exit") || exit 0

# Handle exit option
if [ "$component" = "Exit" ]; then
Expand Down Expand Up @@ -290,7 +400,7 @@ run_prerequisite_commands

while true; do
# Show main menu
environment=$(gum choose "dev" "production" "Exit")
environment=$(flow_choose "dev" "production" "Exit") || exit 0

# Handle exit option
if [ "$environment" = "Exit" ]; then
Expand Down
Loading