kdebug 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kdebug
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Universal Kubernetes Debug Container Utility
5
5
  Project-URL: Homepage, https://github.com/jessegoodier/kdebug
6
6
  Project-URL: Repository, https://github.com/jessegoodier/kdebug
@@ -13,7 +13,7 @@ Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Operating System :: MacOS
14
14
  Classifier: Operating System :: POSIX :: Linux
15
15
  Classifier: Programming Language :: Python :: 3
16
- Requires-Python: >=3.8
16
+ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
 
19
19
  # kdebug - Universal Kubernetes Debug and File Copy Container Utility
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kdebug"
7
- version = "0.2.2"
7
+ version = "0.3.0"
8
8
  description = "Universal Kubernetes Debug Container Utility"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
- requires-python = ">=3.8"
11
+ requires-python = ">=3.9"
12
12
  authors = [{ name = "Jesse Goodier" }]
13
13
  keywords = ["kubernetes", "debug", "kubectl", "cli"]
14
14
  classifiers = [
@@ -23,6 +23,16 @@ classifiers = [
23
23
  [project.scripts]
24
24
  kdebug = "kdebug.cli:main"
25
25
 
26
+ [tool.hatch.build]
27
+ include = ["src/kdebug"]
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/kdebug"]
31
+ artifacts = ["src/kdebug/completions/*"]
32
+
33
+ [tool.hatch.build.targets.sdist]
34
+ include = ["src/kdebug"]
35
+
26
36
  [project.urls]
27
37
  Homepage = "https://github.com/jessegoodier/kdebug"
28
38
  Repository = "https://github.com/jessegoodier/kdebug"
@@ -8,7 +8,7 @@ interactive shell access and backup capabilities.
8
8
 
9
9
  Usage Examples:
10
10
  # Interactive session with controller
11
- ./kdebug.py -n kubecost --controller sts --controller-name aggregator --container aggregator --cmd bash
11
+ ./kdebug.py -n kubecost --controller sts/aggregator --container aggregator --cmd bash
12
12
 
13
13
  # Interactive session with direct pod
14
14
  ./kdebug.py -n kubecost --pod aggregator-0 --container aggregator
@@ -17,10 +17,11 @@ Usage Examples:
17
17
  ./kdebug.py -n kubecost --pod aggregator-0 --container aggregator --backup /var/configs
18
18
 
19
19
  # Using deployment
20
- ./kdebug.py -n myapp --controller deployment --controller-name frontend --cmd sh
20
+ ./kdebug.py -n myapp --controller deploy/frontend --cmd sh
21
21
  """
22
22
 
23
23
  import argparse
24
+ import importlib.resources
24
25
  import json
25
26
  import os
26
27
  import subprocess
@@ -455,18 +456,12 @@ def select_pod(args) -> Optional[Dict]:
455
456
 
456
457
  # Controller-based selection
457
458
  if args.controller:
458
- if not args.controller_name:
459
- print(
460
- "Error: --controller-name is required when using --controller",
461
- file=sys.stderr,
462
- )
463
- return None
464
-
465
- pods = get_pods_by_controller(args.controller, args.controller_name, namespace)
459
+ controller_type, controller_name = args.controller
460
+ pods = get_pods_by_controller(controller_type, controller_name, namespace)
466
461
 
467
462
  if not pods:
468
463
  print(
469
- f"No pods found for {args.controller} '{args.controller_name}'",
464
+ f"No pods found for {controller_type} '{controller_name}'",
470
465
  file=sys.stderr,
471
466
  )
472
467
  return None
@@ -998,246 +993,43 @@ def cleanup_debug_container(
998
993
  return True
999
994
 
1000
995
 
1001
- def generate_bash_completion() -> str:
1002
- """Generate bash completion script."""
1003
- return """# kdebug bash completion
1004
- # Source this file or add to ~/.bashrc:
1005
- # source <(kdebug --completions bash)
1006
- # Or:
1007
- # source /path/to/completions/kdebug.bash
1008
-
1009
- _kdebug_get_contexts() {
1010
- kubectl config get-contexts -o name 2>/dev/null
1011
- }
1012
-
1013
- _kdebug_get_namespaces() {
1014
- local kubectl_args=$(_kdebug_get_kubectl_args)
1015
- kubectl $kubectl_args get namespaces -o jsonpath='{.items[*].metadata.name}' 2>/dev/null
1016
- }
1017
-
1018
- _kdebug_get_pods() {
1019
- local ns="${1:-default}"
1020
- local kubectl_args=$(_kdebug_get_kubectl_args)
1021
- kubectl $kubectl_args get pods -n "$ns" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null
1022
- }
1023
-
1024
- _kdebug_get_controllers() {
1025
- local ns="${1:-default}"
1026
- local controller_type="$2"
1027
- local kubectl_args=$(_kdebug_get_kubectl_args)
1028
- case "$controller_type" in
1029
- deployment|deploy)
1030
- kubectl $kubectl_args get deployments -n "$ns" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null
1031
- ;;
1032
- statefulset|sts)
1033
- kubectl $kubectl_args get statefulsets -n "$ns" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null
1034
- ;;
1035
- daemonset|ds)
1036
- kubectl $kubectl_args get daemonsets -n "$ns" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null
1037
- ;;
1038
- esac
1039
- }
1040
-
1041
- _kdebug_get_kubectl_args() {
1042
- local i args=""
1043
- for ((i=1; i < ${#COMP_WORDS[@]}; i++)); do
1044
- case "${COMP_WORDS[i]}" in
1045
- --context)
1046
- if [[ $((i+1)) -lt ${#COMP_WORDS[@]} ]]; then
1047
- args="$args --context=${COMP_WORDS[$((i+1))]}"
1048
- fi
1049
- ;;
1050
- --context=*)
1051
- args="$args ${COMP_WORDS[i]}"
1052
- ;;
1053
- --kubeconfig)
1054
- if [[ $((i+1)) -lt ${#COMP_WORDS[@]} ]]; then
1055
- args="$args --kubeconfig=${COMP_WORDS[$((i+1))]}"
1056
- fi
1057
- ;;
1058
- --kubeconfig=*)
1059
- args="$args ${COMP_WORDS[i]}"
1060
- ;;
1061
- esac
1062
- done
1063
- echo "$args"
1064
- }
1065
-
1066
- _kdebug_get_namespace_from_args() {
1067
- local i
1068
- for ((i=1; i < ${#COMP_WORDS[@]}; i++)); do
1069
- case "${COMP_WORDS[i]}" in
1070
- -n|--namespace)
1071
- if [[ $((i+1)) -lt ${#COMP_WORDS[@]} ]]; then
1072
- echo "${COMP_WORDS[$((i+1))]}"
1073
- return
1074
- fi
1075
- ;;
1076
- -n=*|--namespace=*)
1077
- echo "${COMP_WORDS[i]#*=}"
1078
- return
1079
- ;;
1080
- esac
1081
- done
1082
- local kubectl_args=$(_kdebug_get_kubectl_args)
1083
- kubectl $kubectl_args config view --minify -o jsonpath='{..namespace}' 2>/dev/null || echo "default"
1084
- }
1085
-
1086
- _kdebug_get_controller_from_args() {
1087
- local i
1088
- for ((i=1; i < ${#COMP_WORDS[@]}; i++)); do
1089
- case "${COMP_WORDS[i]}" in
1090
- --controller)
1091
- if [[ $((i+1)) -lt ${#COMP_WORDS[@]} ]]; then
1092
- echo "${COMP_WORDS[$((i+1))]}"
1093
- return
1094
- fi
1095
- ;;
1096
- --controller=*)
1097
- echo "${COMP_WORDS[i]#*=}"
1098
- return
1099
- ;;
1100
- esac
1101
- done
1102
- }
1103
-
1104
- _kdebug() {
1105
- local cur prev words cword
1106
- _init_completion || return
1107
-
1108
- local opts="--pod --controller --controller-name -n --namespace --context --kubeconfig
1109
- --container --debug-image --cmd --cd-into --backup --compress --as-root
1110
- --debug --completions -V --version --help -h"
1111
-
1112
- local controller_types="deployment deploy statefulset sts daemonset ds"
1113
-
1114
- case "$prev" in
1115
- -n|--namespace)
1116
- COMPREPLY=($(compgen -W "$(_kdebug_get_namespaces)" -- "$cur"))
1117
- return
1118
- ;;
1119
- --context)
1120
- COMPREPLY=($(compgen -W "$(_kdebug_get_contexts)" -- "$cur"))
1121
- return
1122
- ;;
1123
- --kubeconfig)
1124
- _filedir
1125
- return
1126
- ;;
1127
- --pod)
1128
- local ns=$(_kdebug_get_namespace_from_args)
1129
- COMPREPLY=($(compgen -W "$(_kdebug_get_pods "$ns")" -- "$cur"))
1130
- return
1131
- ;;
1132
- --controller)
1133
- COMPREPLY=($(compgen -W "$controller_types" -- "$cur"))
1134
- return
1135
- ;;
1136
- --controller-name)
1137
- local ns=$(_kdebug_get_namespace_from_args)
1138
- local ct=$(_kdebug_get_controller_from_args)
1139
- if [[ -n "$ct" ]]; then
1140
- COMPREPLY=($(compgen -W "$(_kdebug_get_controllers "$ns" "$ct")" -- "$cur"))
1141
- fi
1142
- return
1143
- ;;
1144
- --container|--debug-image|--cmd|--cd-into|--backup)
1145
- # These take arbitrary values, no completion
1146
- return
1147
- ;;
1148
- --completions)
1149
- COMPREPLY=($(compgen -W "bash zsh" -- "$cur"))
1150
- return
1151
- ;;
1152
- esac
1153
-
1154
- if [[ "$cur" == -* ]]; then
1155
- COMPREPLY=($(compgen -W "$opts" -- "$cur"))
1156
- return
1157
- fi
1158
- }
1159
-
1160
- complete -F _kdebug kdebug
1161
- """
1162
-
1163
-
1164
- def generate_zsh_completion() -> str:
1165
- """Generate zsh completion script."""
1166
- return """#compdef kdebug
1167
- # kdebug zsh completion
1168
- # Install: kdebug --completions zsh > ~/.zsh/completions/_kdebug
1169
- # Or: source <(kdebug --completions zsh)
1170
-
1171
- _kdebug_kubectl_args() {
1172
- local args=""
1173
- [[ -n "${opt_args[--context]}" ]] && args="$args --context=${opt_args[--context]}"
1174
- [[ -n "${opt_args[--kubeconfig]}" ]] && args="$args --kubeconfig=${opt_args[--kubeconfig]}"
1175
- echo "$args"
1176
- }
1177
-
1178
- _kdebug_contexts() {
1179
- local -a contexts
1180
- contexts=(${(f)"$(kubectl config get-contexts -o name 2>/dev/null)"})
1181
- _describe 'context' contexts
1182
- }
1183
-
1184
- _kdebug_namespaces() {
1185
- local kubectl_args=$(_kdebug_kubectl_args)
1186
- local -a namespaces
1187
- namespaces=(${(f)"$(kubectl $kubectl_args get namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\\n"}{end}' 2>/dev/null)"})
1188
- _describe 'namespace' namespaces
1189
- }
996
+ def _output_completion_script(shell: str) -> None:
997
+ """Output the shell completion script and exit."""
998
+ files = {"bash": "kdebug.bash", "zsh": "_kdebug", "fish": "kdebug.fish"}
999
+ filename = files.get(shell)
1000
+ if not filename:
1001
+ print(f"Unknown shell: {shell}", file=sys.stderr)
1002
+ sys.exit(1)
1190
1003
 
1191
- _kdebug_pods() {
1192
- local ns="${opt_args[-n]:-${opt_args[--namespace]:-default}}"
1193
- local kubectl_args=$(_kdebug_kubectl_args)
1194
- local -a pods
1195
- pods=(${(f)"$(kubectl $kubectl_args get pods -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\\n"}{end}' 2>/dev/null)"})
1196
- _describe 'pod' pods
1197
- }
1004
+ try:
1005
+ completions_pkg = importlib.resources.files("kdebug.completions")
1006
+ script = (completions_pkg / filename).read_text()
1007
+ print(script)
1008
+ except Exception as e:
1009
+ print(f"Error reading completion script: {e}", file=sys.stderr)
1010
+ sys.exit(1)
1198
1011
 
1199
- _kdebug_controller_names() {
1200
- local ns="${opt_args[-n]:-${opt_args[--namespace]:-default}}"
1201
- local ct="${opt_args[--controller]:-deployment}"
1202
- local kubectl_args=$(_kdebug_kubectl_args)
1203
- local resource
1204
- case "$ct" in
1205
- deployment|deploy) resource="deployments" ;;
1206
- statefulset|sts) resource="statefulsets" ;;
1207
- daemonset|ds) resource="daemonsets" ;;
1208
- *) resource="deployments" ;;
1209
- esac
1210
- local -a names
1211
- names=(${(f)"$(kubectl $kubectl_args get "$resource" -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\\n"}{end}' 2>/dev/null)"})
1212
- _describe 'controller name' names
1213
- }
1214
1012
 
1215
- _kdebug() {
1216
- local -a args
1217
- args=(
1218
- '(-V --version)'{-V,--version}'[Show version and exit]'
1219
- '(-h --help)'{-h,--help}'[Show help message]'
1220
- '--pod[Pod name for direct selection]:pod:_kdebug_pods'
1221
- '--controller[Controller type]:type:(deployment deploy statefulset sts daemonset ds)'
1222
- '--controller-name[Controller name]:name:_kdebug_controller_names'
1223
- '(-n --namespace)'{-n,--namespace}'[Kubernetes namespace]:namespace:_kdebug_namespaces'
1224
- '--context[Kubernetes context to use]:context:_kdebug_contexts'
1225
- '--kubeconfig[Path to kubeconfig file]:path:_files'
1226
- '--container[Target container for process namespace sharing]:container:'
1227
- '--debug-image[Debug container image]:image:'
1228
- '--cmd[Command to run in debug container]:command:'
1229
- '--cd-into[Change to directory on start]:directory:_files -/'
1230
- '--backup[Copy path from pod to local backups]:path:'
1231
- '--compress[Compress backup as tar.gz]'
1232
- '--as-root[Run debug container as root]'
1233
- '--debug[Show kubectl commands being executed]'
1234
- '--completions[Output shell completion script]:shell:(bash zsh)'
1235
- )
1236
- _arguments -s $args
1237
- }
1013
+ def parse_controller_arg(value: str) -> Tuple[str, str]:
1014
+ """Parse --controller TYPE/NAME format and return (controller_type, controller_name).
1238
1015
 
1239
- _kdebug "$@"
1240
- """
1016
+ Raises argparse.ArgumentTypeError on invalid input.
1017
+ """
1018
+ if "/" not in value:
1019
+ raise argparse.ArgumentTypeError(
1020
+ f"Invalid format '{value}'. Expected TYPE/NAME (e.g. sts/myapp, deploy/frontend)."
1021
+ )
1022
+ controller_type, controller_name = value.split("/", 1)
1023
+ if not controller_name:
1024
+ raise argparse.ArgumentTypeError(
1025
+ f"Missing controller name after '/'. Expected TYPE/NAME (e.g. sts/myapp)."
1026
+ )
1027
+ if controller_type.lower() not in CONTROLLER_ALIASES:
1028
+ valid_types = ", ".join(sorted(CONTROLLER_ALIASES.keys()))
1029
+ raise argparse.ArgumentTypeError(
1030
+ f"Unknown controller type '{controller_type}'. Valid types: {valid_types}"
1031
+ )
1032
+ return (controller_type, controller_name)
1241
1033
 
1242
1034
 
1243
1035
  class KdebugHelpFormatter(argparse.RawDescriptionHelpFormatter):
@@ -1258,12 +1050,13 @@ def main():
1258
1050
  Usage:
1259
1051
  kdebug [options] Interactive TUI mode
1260
1052
  kdebug --pod POD [options] Direct pod selection
1261
- kdebug --controller TYPE --controller-name NAME Controller selection""",
1053
+ kdebug --controller TYPE/NAME [options] Controller selection""",
1262
1054
  formatter_class=KdebugHelpFormatter,
1263
1055
  epilog="""Examples:
1264
1056
  kdebug # Interactive TUI
1265
1057
  kdebug -n prod --pod api-0 # Direct pod
1266
- kdebug --controller sts --controller-name db # StatefulSet pod
1058
+ kdebug --controller sts/db # StatefulSet pod
1059
+ kdebug --controller deploy/frontend --cmd sh # Deployment pod
1267
1060
  kdebug --pod web-0 --backup /app/config # Backup files""",
1268
1061
  )
1269
1062
 
@@ -1279,14 +1072,9 @@ Usage:
1279
1072
  )
1280
1073
  target_group.add_argument(
1281
1074
  "--controller",
1282
- choices=list(CONTROLLER_ALIASES.keys()),
1283
- metavar="TYPE",
1284
- help="Controller type: deployment, sts, ds (or full names)",
1285
- )
1286
- target_group.add_argument(
1287
- "--controller-name",
1288
- metavar="NAME",
1289
- help="Controller name (required with --controller)",
1075
+ type=parse_controller_arg,
1076
+ metavar="TYPE/NAME",
1077
+ help="Controller as TYPE/NAME (e.g. sts/myapp, deploy/frontend)",
1290
1078
  )
1291
1079
 
1292
1080
  # Options arguments
@@ -1349,7 +1137,7 @@ Usage:
1349
1137
  )
1350
1138
  util_group.add_argument(
1351
1139
  "--completions",
1352
- choices=["bash", "zsh"],
1140
+ choices=["bash", "zsh", "fish"],
1353
1141
  metavar="SHELL",
1354
1142
  help="Output shell completion script",
1355
1143
  )
@@ -1358,10 +1146,7 @@ Usage:
1358
1146
 
1359
1147
  # Handle --completions early
1360
1148
  if args.completions:
1361
- if args.completions == "bash":
1362
- print(generate_bash_completion())
1363
- else:
1364
- print(generate_zsh_completion())
1149
+ _output_completion_script(args.completions)
1365
1150
  sys.exit(0)
1366
1151
 
1367
1152
  # Set debug mode and kubectl global options
@@ -1370,10 +1155,6 @@ Usage:
1370
1155
  KUBECTL_CONTEXT = args.context
1371
1156
  KUBECTL_KUBECONFIG = args.kubeconfig
1372
1157
 
1373
- # Validate arguments - allow interactive mode if no pod/controller specified
1374
- if args.controller and not args.controller_name:
1375
- parser.error("--controller-name is required when using --controller")
1376
-
1377
1158
  # Select pod
1378
1159
  pod = select_pod(args)
1379
1160
  if not pod:
File without changes
@@ -31,20 +31,41 @@ _kdebug_pods() {
31
31
  _describe 'pod' pods
32
32
  }
33
33
 
34
- _kdebug_controller_names() {
34
+ _kdebug_controllers() {
35
35
  local ns="${opt_args[-n]:-${opt_args[--namespace]:-default}}"
36
- local ct="${opt_args[--controller]:-deployment}"
37
36
  local kubectl_args=$(_kdebug_kubectl_args)
38
- local resource
39
- case "$ct" in
40
- deployment|deploy) resource="deployments" ;;
41
- statefulset|sts) resource="statefulsets" ;;
42
- daemonset|ds) resource="daemonsets" ;;
43
- *) resource="deployments" ;;
44
- esac
45
- local -a names
46
- names=(${(f)"$(kubectl $kubectl_args get "$resource" -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null)"})
47
- _describe 'controller name' names
37
+ local cur_word="${words[CURRENT]}"
38
+
39
+ if [[ "$cur_word" == */* ]]; then
40
+ # User typed TYPE/ - complete the name
41
+ local ct="${cur_word%%/*}"
42
+ local resource
43
+ case "$ct" in
44
+ deployment|deploy) resource="deployments" ;;
45
+ statefulset|sts) resource="statefulsets" ;;
46
+ daemonset|ds) resource="daemonsets" ;;
47
+ *) resource="deployments" ;;
48
+ esac
49
+ local -a names
50
+ names=(${(f)"$(kubectl $kubectl_args get "$resource" -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null)"})
51
+ local -a completions
52
+ for name in "${names[@]}"; do
53
+ completions+=("${ct}/${name}")
54
+ done
55
+ compadd -Q -- "${completions[@]}"
56
+ else
57
+ # Complete the type prefix
58
+ local -a prefixes
59
+ prefixes=(
60
+ 'deployment/:Deployment'
61
+ 'deploy/:Deployment (short)'
62
+ 'statefulset/:StatefulSet'
63
+ 'sts/:StatefulSet (short)'
64
+ 'daemonset/:DaemonSet'
65
+ 'ds/:DaemonSet (short)'
66
+ )
67
+ _describe 'controller type' prefixes -S ''
68
+ fi
48
69
  }
49
70
 
50
71
  _kdebug() {
@@ -53,8 +74,7 @@ _kdebug() {
53
74
  '(-V --version)'{-V,--version}'[Show version and exit]'
54
75
  '(-h --help)'{-h,--help}'[Show help message]'
55
76
  '--pod[Pod name for direct selection]:pod:_kdebug_pods'
56
- '--controller[Controller type]:type:(deployment deploy statefulset sts daemonset ds)'
57
- '--controller-name[Controller name]:name:_kdebug_controller_names'
77
+ '--controller[Controller as TYPE/NAME]:controller:_kdebug_controllers'
58
78
  '(-n --namespace)'{-n,--namespace}'[Kubernetes namespace]:namespace:_kdebug_namespaces'
59
79
  '--context[Kubernetes context to use]:context:_kdebug_contexts'
60
80
  '--kubeconfig[Path to kubeconfig file]:path:_files'
@@ -66,10 +86,9 @@ _kdebug() {
66
86
  '--compress[Compress backup as tar.gz]'
67
87
  '--as-root[Run debug container as root]'
68
88
  '--debug[Show kubectl commands being executed]'
69
- '--completions[Output shell completion script]:shell:(bash zsh)'
89
+ '--completions[Output shell completion script]:shell:(bash zsh fish)'
70
90
  )
71
91
  _arguments -s $args
72
92
  }
73
93
 
74
94
  _kdebug "$@"
75
-
@@ -81,33 +81,15 @@ _kdebug_get_namespace_from_args() {
81
81
  kubectl $kubectl_args config view --minify -o jsonpath='{..namespace}' 2>/dev/null || echo "default"
82
82
  }
83
83
 
84
- _kdebug_get_controller_from_args() {
85
- local i
86
- for ((i=1; i < ${#COMP_WORDS[@]}; i++)); do
87
- case "${COMP_WORDS[i]}" in
88
- --controller)
89
- if [[ $((i+1)) -lt ${#COMP_WORDS[@]} ]]; then
90
- echo "${COMP_WORDS[$((i+1))]}"
91
- return
92
- fi
93
- ;;
94
- --controller=*)
95
- echo "${COMP_WORDS[i]#*=}"
96
- return
97
- ;;
98
- esac
99
- done
100
- }
101
-
102
84
  _kdebug() {
103
85
  local cur prev words cword
104
86
  _init_completion || return
105
87
 
106
- local opts="--pod --controller --controller-name -n --namespace --context --kubeconfig
88
+ local opts="--pod --controller -n --namespace --context --kubeconfig
107
89
  --container --debug-image --cmd --cd-into --backup --compress --as-root
108
90
  --debug --completions -V --version --help -h"
109
91
 
110
- local controller_types="deployment deploy statefulset sts daemonset ds"
92
+ local controller_prefixes="deployment/ deploy/ statefulset/ sts/ daemonset/ ds/"
111
93
 
112
94
  case "$prev" in
113
95
  -n|--namespace)
@@ -128,14 +110,20 @@ _kdebug() {
128
110
  return
129
111
  ;;
130
112
  --controller)
131
- COMPREPLY=($(compgen -W "$controller_types" -- "$cur"))
132
- return
133
- ;;
134
- --controller-name)
135
- local ns=$(_kdebug_get_namespace_from_args)
136
- local ct=$(_kdebug_get_controller_from_args)
137
- if [[ -n "$ct" ]]; then
138
- COMPREPLY=($(compgen -W "$(_kdebug_get_controllers "$ns" "$ct")" -- "$cur"))
113
+ # Complete TYPE/NAME - if cur contains /, complete the name part
114
+ if [[ "$cur" == */* ]]; then
115
+ local ct="${cur%%/*}"
116
+ local ns=$(_kdebug_get_namespace_from_args)
117
+ local names=$(_kdebug_get_controllers "$ns" "$ct")
118
+ local completions=""
119
+ for name in $names; do
120
+ completions="$completions ${ct}/${name}"
121
+ done
122
+ COMPREPLY=($(compgen -W "$completions" -- "$cur"))
123
+ else
124
+ COMPREPLY=($(compgen -W "$controller_prefixes" -- "$cur"))
125
+ # Don't add trailing space after type prefix
126
+ compopt -o nospace
139
127
  fi
140
128
  return
141
129
  ;;
@@ -144,7 +132,7 @@ _kdebug() {
144
132
  return
145
133
  ;;
146
134
  --completions)
147
- COMPREPLY=($(compgen -W "bash zsh" -- "$cur"))
135
+ COMPREPLY=($(compgen -W "bash zsh fish" -- "$cur"))
148
136
  return
149
137
  ;;
150
138
  esac
@@ -156,4 +144,3 @@ _kdebug() {
156
144
  }
157
145
 
158
146
  complete -F _kdebug kdebug
159
-
@@ -0,0 +1,121 @@
1
+ # kdebug fish completion
2
+ # Install: kdebug --completions fish | source
3
+ # Or: kdebug --completions fish > ~/.config/fish/completions/kdebug.fish
4
+
5
+ function __kdebug_get_kubectl_args
6
+ set -l tokens (commandline -opc)
7
+ set -l args
8
+ set -l i 2
9
+ while test $i -le (count $tokens)
10
+ switch $tokens[$i]
11
+ case --context
12
+ set -l next (math $i + 1)
13
+ if test $next -le (count $tokens)
14
+ set -a args --context=$tokens[$next]
15
+ end
16
+ case '--context=*'
17
+ set -a args $tokens[$i]
18
+ case --kubeconfig
19
+ set -l next (math $i + 1)
20
+ if test $next -le (count $tokens)
21
+ set -a args --kubeconfig=$tokens[$next]
22
+ end
23
+ case '--kubeconfig=*'
24
+ set -a args $tokens[$i]
25
+ end
26
+ set i (math $i + 1)
27
+ end
28
+ echo $args
29
+ end
30
+
31
+ function __kdebug_get_namespace_from_args
32
+ set -l tokens (commandline -opc)
33
+ set -l i 2
34
+ while test $i -le (count $tokens)
35
+ switch $tokens[$i]
36
+ case -n --namespace
37
+ set -l next (math $i + 1)
38
+ if test $next -le (count $tokens)
39
+ echo $tokens[$next]
40
+ return
41
+ end
42
+ case '-n=*' '--namespace=*'
43
+ string replace -r '^[^=]+=' '' $tokens[$i]
44
+ return
45
+ end
46
+ set i (math $i + 1)
47
+ end
48
+ set -l kubectl_args (__kdebug_get_kubectl_args)
49
+ set -l ns (kubectl $kubectl_args config view --minify -o jsonpath='{..namespace}' 2>/dev/null)
50
+ if test -n "$ns"
51
+ echo $ns
52
+ else
53
+ echo default
54
+ end
55
+ end
56
+
57
+ function __kdebug_get_contexts
58
+ kubectl config get-contexts -o name 2>/dev/null
59
+ end
60
+
61
+ function __kdebug_get_namespaces
62
+ set -l kubectl_args (__kdebug_get_kubectl_args)
63
+ kubectl $kubectl_args get namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null
64
+ end
65
+
66
+ function __kdebug_get_pods
67
+ set -l ns (__kdebug_get_namespace_from_args)
68
+ set -l kubectl_args (__kdebug_get_kubectl_args)
69
+ kubectl $kubectl_args get pods -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null
70
+ end
71
+
72
+ function __kdebug_get_controllers
73
+ set -l ns (__kdebug_get_namespace_from_args)
74
+ set -l kubectl_args (__kdebug_get_kubectl_args)
75
+ set -l cur (commandline -ct)
76
+
77
+ if string match -q '*/*' -- "$cur"
78
+ # User typed TYPE/ - complete the name part
79
+ set -l ct (string replace -r '/.*' '' -- "$cur")
80
+ set -l resource
81
+ switch $ct
82
+ case deployment deploy
83
+ set resource deployments
84
+ case statefulset sts
85
+ set resource statefulsets
86
+ case daemonset ds
87
+ set resource daemonsets
88
+ case '*'
89
+ return
90
+ end
91
+ for name in (kubectl $kubectl_args get "$resource" -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null)
92
+ echo "$ct/$name"
93
+ end
94
+ else
95
+ # Complete type prefixes
96
+ printf '%s\n' deployment/ deploy/ statefulset/ sts/ daemonset/ ds/
97
+ end
98
+ end
99
+
100
+ # Disable file completions for kdebug
101
+ complete -c kdebug -f
102
+
103
+ # Target selection
104
+ complete -c kdebug -l pod -d 'Pod name for direct selection' -xa '(__kdebug_get_pods)'
105
+ complete -c kdebug -l controller -d 'Controller as TYPE/NAME' -xa '(__kdebug_get_controllers)'
106
+
107
+ # Options
108
+ complete -c kdebug -s n -l namespace -d 'Kubernetes namespace' -xa '(__kdebug_get_namespaces)'
109
+ complete -c kdebug -l context -d 'Kubernetes context to use' -xa '(__kdebug_get_contexts)'
110
+ complete -c kdebug -l kubeconfig -d 'Path to kubeconfig file' -rF
111
+ complete -c kdebug -l container -d 'Target container for process namespace sharing' -x
112
+ complete -c kdebug -l debug-image -d 'Debug container image' -x
113
+ complete -c kdebug -l cmd -d 'Command to run in debug container' -x
114
+ complete -c kdebug -l cd-into -d 'Change to directory on start' -rF
115
+ complete -c kdebug -l backup -d 'Copy path from pod to local backups' -x
116
+ complete -c kdebug -l compress -d 'Compress backup as tar.gz'
117
+ complete -c kdebug -l as-root -d 'Run debug container as root'
118
+ complete -c kdebug -l debug -d 'Show kubectl commands being executed'
119
+ complete -c kdebug -l completions -d 'Output shell completion script' -xa 'bash zsh fish'
120
+ complete -c kdebug -s V -l version -d 'Show version and exit'
121
+ complete -c kdebug -s h -l help -d 'Show help message'
@@ -1,10 +0,0 @@
1
- version: 2
2
-
3
- updates:
4
- - package-ecosystem: "github-actions"
5
- directory: "/"
6
- schedule:
7
- interval: "weekly"
8
- open-pull-requests-limit: 10
9
- commit-message:
10
- prefix: "chore(deps)"
@@ -1,40 +0,0 @@
1
- # Uses PyPI Trusted Publisher (OIDC) - no token required
2
- # Configure at: https://pypi.org/manage/project/kdebug/settings/publishing/
3
-
4
- name: Publish to PyPI
5
-
6
- on:
7
- workflow_call:
8
- inputs:
9
- ref:
10
- description: 'Git reference to checkout'
11
- required: false
12
- type: string
13
- release:
14
- types: [published]
15
- workflow_dispatch:
16
-
17
- permissions:
18
- id-token: write
19
- contents: read
20
-
21
- jobs:
22
- publish:
23
- runs-on: ubuntu-latest
24
- environment: pypi
25
- steps:
26
- - name: Check out
27
- uses: actions/checkout@v6
28
- with:
29
- ref: ${{ inputs.ref || github.ref }}
30
-
31
- - name: Install uv
32
- uses: astral-sh/setup-uv@v7
33
- with:
34
- version: "latest"
35
-
36
- - name: Build package
37
- run: uv build
38
-
39
- - name: Publish package
40
- run: uv publish --trusted-publishing always
@@ -1,87 +0,0 @@
1
- name: Create Release
2
-
3
- on:
4
- workflow_dispatch:
5
- inputs:
6
- release_type:
7
- description: 'Release type'
8
- required: true
9
- default: 'patch'
10
- type: choice
11
- options:
12
- - patch
13
- - minor
14
- - major
15
-
16
- permissions:
17
- contents: write
18
- id-token: write
19
-
20
- jobs:
21
- release:
22
- runs-on: ubuntu-latest
23
- outputs:
24
- version: ${{ steps.new.outputs.version }}
25
- steps:
26
- - uses: actions/checkout@v6
27
- with:
28
- fetch-depth: 0
29
-
30
- - name: Configure Git
31
- run: |
32
- git config user.name "github-actions[bot]"
33
- git config user.email "github-actions[bot]@users.noreply.github.com"
34
-
35
- - name: Get current version
36
- id: current
37
- run: |
38
- VERSION=$(grep -oP '^version = "\K[^"]+' pyproject.toml)
39
- echo "version=$VERSION" >> $GITHUB_OUTPUT
40
-
41
- - name: Calculate new version
42
- id: new
43
- run: |
44
- IFS='.' read -r major minor patch <<< "${{ steps.current.outputs.version }}"
45
- case "${{ inputs.release_type }}" in
46
- major) major=$((major + 1)); minor=0; patch=0 ;;
47
- minor) minor=$((minor + 1)); patch=0 ;;
48
- patch) patch=$((patch + 1)) ;;
49
- esac
50
- echo "version=${major}.${minor}.${patch}" >> $GITHUB_OUTPUT
51
-
52
- - name: Update version in pyproject.toml
53
- run: |
54
- sed -i 's/^version = "[^"]*"/version = "${{ steps.new.outputs.version }}"/' pyproject.toml
55
-
56
- - name: Commit and tag
57
- run: |
58
- git add pyproject.toml
59
- git commit -m "Release v${{ steps.new.outputs.version }}"
60
- git tag "v${{ steps.new.outputs.version }}"
61
-
62
- - name: Push changes
63
- run: |
64
- git push origin HEAD:${{ github.ref_name }}
65
- git push --tags
66
-
67
- - name: Create GitHub Release
68
- env:
69
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70
- run: |
71
- gh release create "v${{ steps.new.outputs.version }}" \
72
- --generate-notes \
73
- --latest
74
-
75
- update-homebrew:
76
- needs: release
77
- uses: ./.github/workflows/update-homebrew.yml
78
- with:
79
- version: v${{ needs.release.outputs.version }}
80
- secrets: inherit
81
-
82
- publish-pypi:
83
- needs: release
84
- uses: ./.github/workflows/pypi-publish.yml
85
- with:
86
- ref: v${{ needs.release.outputs.version }}
87
- secrets: inherit
@@ -1,37 +0,0 @@
1
- name: Update Homebrew Tap
2
-
3
- on:
4
- workflow_call:
5
- inputs:
6
- version:
7
- description: 'Version tag (e.g., v1.0.0)'
8
- required: false
9
- type: string
10
-
11
- jobs:
12
- update-homebrew-tap:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - name: Get version
16
- id: release-info
17
- run: |
18
- VERSION="${{ inputs.version }}"
19
- VERSION="${VERSION#v}" # Strip 'v' prefix
20
- echo "version=$VERSION" >> $GITHUB_OUTPUT
21
- echo "Release version: $VERSION"
22
-
23
- - name: Trigger Homebrew tap update
24
- env:
25
- GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
26
- run: |
27
- gh workflow run update-formula.yml \
28
- --repo jessegoodier/homebrew-kdebug \
29
- -f version="${{ steps.release-info.outputs.version }}" || {
30
- echo "::warning::Failed to trigger Homebrew update. Ensure HOMEBREW_TAP_TOKEN secret is set with repo scope for jessegoodier/homebrew-kdebug."
31
- echo "The daily schedule in homebrew-kdebug will pick up the new version from PyPI automatically."
32
- }
33
-
34
- - name: Summary
35
- run: |
36
- echo "### Homebrew tap update triggered for kdebug ${{ steps.release-info.outputs.version }}" >> $GITHUB_STEP_SUMMARY
37
- echo "The [homebrew-kdebug](https://github.com/jessegoodier/homebrew-kdebug) update-formula workflow has been dispatched." >> $GITHUB_STEP_SUMMARY
kdebug-0.2.2/AGENTS.md DELETED
@@ -1,163 +0,0 @@
1
- # AGENTS.md - AI Assistant Guide
2
-
3
- This file helps AI coding assistants understand the kdebug project.
4
-
5
- ## Project Overview
6
-
7
- kdebug is a Python CLI tool for launching ephemeral debug containers in Kubernetes pods. It provides interactive shell access, backup capabilities, and a TUI for pod selection.
8
-
9
- ## Project Structure
10
-
11
- ```
12
- kdebug/
13
- ├── pyproject.toml # Package metadata and build config (version source of truth)
14
- ├── src/
15
- │ └── kdebug/
16
- │ ├── __init__.py # Package init with __version__ from importlib.metadata
17
- │ └── cli.py # Main CLI code
18
- ├── completions/
19
- │ ├── kdebug.bash # Bash completion script (generated)
20
- │ └── _kdebug # Zsh completion script (generated)
21
- ├── README.md # User documentation
22
- ├── AGENTS.md # This file
23
- └── .github/
24
- └── workflows/
25
- └── release.yml # Release automation (updates pyproject.toml)
26
- ```
27
-
28
- ## Key Architecture
29
-
30
- - **Python package**: Installable via `uv tool install kdebug` or `pip install .`
31
- - **Entry point**: `kdebug` command maps to `kdebug.cli:main`
32
- - **Version**: Single source of truth in `pyproject.toml`, accessed via `importlib.metadata`
33
- - **No external dependencies**: Uses Python stdlib only
34
- - **Completion scripts are generated**: The functions `generate_bash_completion()` and `generate_zsh_completion()` in `src/kdebug/cli.py` produce the completion files
35
- - **Global state pattern**: Module-level variables (`DEBUG_MODE`, `KUBECTL_CONTEXT`, `KUBECTL_KUBECONFIG`) are set after argument parsing
36
-
37
- ## Making Changes
38
-
39
- ### Adding a new CLI argument
40
-
41
- 1. Add the argument to the appropriate `parser.add_argument_group()` in `main()`
42
- 2. If it affects kubectl commands, update the relevant helper function or `kubectl_base_cmd()`
43
- 3. Update `generate_bash_completion()` - add to `opts` list and add completion case if needed
44
- 4. Update `generate_zsh_completion()` - add to `args` array with appropriate completer
45
- 5. Regenerate completion files (see below)
46
- 6. Update README.md if user-facing
47
-
48
- ### Modifying kubectl commands
49
-
50
- All kubectl commands should use `kubectl_base_cmd()` to ensure `--context` and `--kubeconfig` are passed through:
51
-
52
- ```python
53
- cmd = f"{kubectl_base_cmd()} get pods -n {namespace} -o json"
54
- ```
55
-
56
- ### Regenerating completion files
57
-
58
- After modifying the completion generators:
59
-
60
- ```bash
61
- # Install package in development mode first
62
- uv pip install -e .
63
-
64
- # Then regenerate completions
65
- kdebug --completions bash > completions/kdebug.bash
66
- kdebug --completions zsh > completions/_kdebug
67
- ```
68
-
69
- ## Testing
70
-
71
- ### Manual testing
72
-
73
- ```bash
74
- # Install in development mode
75
- uv pip install -e .
76
-
77
- # Verify help output
78
- kdebug --help
79
-
80
- # Verify version
81
- kdebug --version
82
-
83
- # Test with debug mode to see kubectl commands
84
- kdebug --debug -n <namespace>
85
-
86
- # Test argument combinations
87
- kdebug --context <ctx> --kubeconfig <path> -n <ns> --pod <pod>
88
- ```
89
-
90
- ### Syntax checks
91
-
92
- ```bash
93
- # Python syntax
94
- python3 -m py_compile src/kdebug/cli.py
95
-
96
- # Bash completion syntax
97
- bash -n completions/kdebug.bash
98
-
99
- # Zsh completion syntax
100
- zsh -n completions/_kdebug
101
- ```
102
-
103
- ### Testing completions
104
-
105
- ```bash
106
- # Bash
107
- source <(kdebug --completions bash)
108
- kdebug --<TAB>
109
-
110
- # Zsh
111
- source <(kdebug --completions zsh)
112
- kdebug --<TAB>
113
- ```
114
-
115
- ## GitHub Actions & Dependencies
116
-
117
- **IMPORTANT: Always use the latest stable versions of GitHub Actions and dependencies to avoid security vulnerabilities (CVEs).**
118
-
119
- ### Current Action Versions (keep updated)
120
-
121
- - `actions/checkout@v6`
122
- - `astral-sh/setup-uv@v7`
123
-
124
- ### Guidelines
125
-
126
- 1. **Never hardcode old versions** - Check the action's repository for the latest major version
127
- 2. **Use major version tags** (e.g., `@v6`) not specific commits or minor versions
128
- 3. **Dependabot is configured** - Review and merge dependabot PRs promptly
129
- 4. **When adding new actions** - Always check for the latest version first via the action's GitHub repo or marketplace page
130
-
131
- ### Workflow Files
132
-
133
- - `.github/workflows/release.yml` - Main release automation
134
- - `.github/workflows/pypi-publish.yml` - PyPI publishing with OIDC trusted publisher
135
- - `.github/workflows/update-homebrew.yml` - Homebrew tap updates
136
-
137
- ## Code Conventions
138
-
139
- - Use `colorize()` for colored output
140
- - Use `run_command()` for executing shell commands
141
- - Use `print_debug_command()` to show commands when `--debug` is enabled
142
- - Error messages go to stderr with `file=sys.stderr`
143
- - Success indicators use green checkmarks: `{colorize('✓', Colors.GREEN)}`
144
- - Error indicators use red X: `{colorize('✗', Colors.RED)}`
145
-
146
- ## Dependencies
147
-
148
- - Python 3.8+ (for `importlib.metadata`)
149
- - kubectl (must be in PATH and configured)
150
- - No pip packages required
151
-
152
- ## Installation
153
-
154
- ```bash
155
- # Via uv (recommended)
156
- uv tool install kdebug
157
-
158
- # Via pip
159
- pip install .
160
-
161
- # Development mode
162
- uv pip install -e .
163
- ```
kdebug-0.2.2/uv.lock DELETED
@@ -1,8 +0,0 @@
1
- version = 1
2
- revision = 3
3
- requires-python = ">=3.8"
4
-
5
- [[package]]
6
- name = "kdebug"
7
- version = "0.2.0"
8
- source = { editable = "." }
File without changes
File without changes
File without changes