Skip to content
Merged
Show file tree
Hide file tree
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
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

env:
SCRIPTS: kill-dev-servers.sh install.sh tests/test-cli.sh

jobs:
test:
# The suite spawns real PIDs and reads /proc, so it needs a Linux runner.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Syntax check
# bash -n only reads its first file argument, so check one at a time.
run: for script in $SCRIPTS; do bash -n "$script"; done

- name: Shellcheck
run: shellcheck $SCRIPTS

- name: CLI tests
run: bash tests/test-cli.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make the binding-order assertion compatible with CI

On the Ubuntu runner's C.UTF-8 locale, the suite fails at tests/test-cli.sh:118: listener discovery sorts the mocked endpoints before rendering them, placing *:3002 before 127.0.0.1:3002, while the assertion requires the reverse order. Running this exact step produces FAIL: second pretty row lacks process metadata or bindings, so the newly added CI job will fail consistently unless the assertion accepts the sorted order (or otherwise ignores endpoint ordering).

Useful? React with 👍 / 👎.

15 changes: 7 additions & 8 deletions kill-dev-servers.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env bash
set -euo pipefail

usage() {
Expand Down Expand Up @@ -276,7 +275,7 @@ discover_listeners_with_ss() {
rest="$line"
while [[ "$rest" =~ pid=([0-9]+) ]]; do
printf '%s\t%s\n' "${BASH_REMATCH[1]}" "$endpoint"
rest="${rest#*pid=${BASH_REMATCH[1]}}"
rest="${rest#*pid="${BASH_REMATCH[1]}"}"
done
done || true
}
Expand Down Expand Up @@ -362,9 +361,9 @@ collect_candidates() {
[[ -z "${seen_bindings["$target_key|$binding"]:-}" ]] || continue
seen_bindings["$target_key|$binding"]=1
if [[ -n "${candidate_bindings[$candidate_index]}" ]]; then
candidate_bindings[$candidate_index]+=$'\n'
candidate_bindings[candidate_index]+=$'\n'
fi
candidate_bindings[$candidate_index]+="$binding"
candidate_bindings[candidate_index]+="$binding"
done <<<"${listener_bindings_by_pid[$pid]:-}"
done
}
Expand All @@ -385,7 +384,7 @@ while IFS=$'\t' read -r pid binding; do
listener_bindings_by_pid[$pid]+=$'\n'
listener_bindings_by_pid[$pid]+="$binding"
fi
done < <(discover_listeners | sort -k1,1n -k2,2 -u)
done < <(discover_listeners | LC_ALL=C sort -k1,1n -k2,2 -u)

declare -a candidate_pids=()
declare -a candidate_pgids=()
Expand Down Expand Up @@ -427,7 +426,7 @@ if [[ -n "$target_pid" ]]; then
printf 'Refusing --pid %s: it is not a current KDS candidate. Run kds --dry-run again.\n' "$target_pid" >&2
exit 1
fi
target_indices=("$selected_index")
selected_indices=("$selected_index")
else
if (( ${#listener_pids[@]} == 0 )); then
echo "No TCP listeners found."
Expand All @@ -437,13 +436,13 @@ else
echo "No matching host dev servers found."
exit 0
fi
target_indices=("${!candidate_pids[@]}")
selected_indices=("${!candidate_pids[@]}")
fi

declare -A terminated_pgids=()
declare -A terminated_pids=()

for index in "${target_indices[@]}"; do
for index in "${selected_indices[@]}"; do
pid="${candidate_pids[$index]}"
pgid="${candidate_pgids[$index]}"
kill_mode="${candidate_modes[$index]}"
Expand Down
10 changes: 5 additions & 5 deletions tests/test-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ fail() {
exit 1
}

preview="$($repo_dir/kill-dev-servers.sh --dry-run)"
short_preview="$($repo_dir/kill-dev-servers.sh -n)"
preview="$("$repo_dir"/kill-dev-servers.sh --dry-run)"
short_preview="$("$repo_dir"/kill-dev-servers.sh -n)"
[[ "$preview" == "$short_preview" ]] || fail '-n differs from --dry-run'
grep -Eq "candidate [0-9]+: pid=$pid_one pgid=81001 cmd=node /work/one/node_modules/.bin/vite \| stop with: kds --pid $pid_one" <<<"$preview" || fail 'first server is not actionable'
grep -Eq "candidate [0-9]+: pid=$pid_two pgid=81002 cmd=next dev --turbopack \| stop with: kds --pid $pid_two" <<<"$preview" || fail 'second server is not actionable'
Expand All @@ -110,17 +110,17 @@ if grep -Fq "pid=$pid_four" <<<"$preview"; then
fi
[[ ! -e "$KILL_LOG" ]] || fail 'dry-run signaled a process'

pretty_preview="$($repo_dir/kill-dev-servers.sh --dry-run --pretty)"
pretty_preview="$("$repo_dir"/kill-dev-servers.sh --dry-run --pretty)"
grep -Eq '^TYPE +ELAPSED +RSS +CPU +BIND +CWD +STOP$' <<<"$pretty_preview" || fail 'pretty preview has no header'
grep -Fq "node 01:23 64 MiB 1.5% 127.0.0.1:3000, [::1]:3001" <<<"$pretty_preview" || fail 'first pretty row lacks process metadata or bindings'
grep -Fq "/work/one" <<<"$pretty_preview" || fail 'first pretty row lacks cwd'
grep -Fq "kds --pid $pid_one" <<<"$pretty_preview" || fail 'first pretty row is not actionable'
grep -Fq "bun 2-03:04:05 512 KiB 0.0% 127.0.0.1:3002, *:3002" <<<"$pretty_preview" || fail 'second pretty row lacks process metadata or bindings'
grep -Fq "bun 2-03:04:05 512 KiB 0.0% *:3002, 127.0.0.1:3002" <<<"$pretty_preview" || fail 'second pretty row lacks process metadata or bindings'
grep -Fq "/work/two with spaces" <<<"$pretty_preview" || fail 'second pretty row lacks cwd'
[[ "$(grep -Fo '127.0.0.1:3000' <<<"$pretty_preview" | wc -l)" -eq 1 ]] || fail 'duplicate bindings were not removed'
[[ ! -e "$KILL_LOG" ]] || fail 'pretty dry-run signaled a process'

missing_preview="$(MISSING_PRETTY_METADATA=1 $repo_dir/kill-dev-servers.sh --dry-run --pretty)"
missing_preview="$(MISSING_PRETTY_METADATA=1 "$repo_dir"/kill-dev-servers.sh --dry-run --pretty)"
grep -Eq '^- +- +- +- +' <<<"$missing_preview" || fail 'missing pretty metadata has no fallbacks'
grep -Fq "kds --pid $pid_one" <<<"$missing_preview" || fail 'missing metadata removed actionable stop command'

Expand Down
Loading