Have Task choose free ports for dev servers (#6145)

This commit is contained in:
James Brunton
2026-04-28 17:26:04 +01:00
committed by GitHub
parent 12a00fe9c5
commit 49f24fa7a9
9 changed files with 216 additions and 114 deletions
+41
View File
@@ -0,0 +1,41 @@
# Prints one free TCP port per preferred port given as an argument.
#
# For each element of -Preferred, emits that port if it's free; otherwise
# emits a random free port in 20000-49999. Probes by attempting to bind a
# TcpListener on loopback. Tracks picks within this run so outputs are
# guaranteed distinct from each other.
param([int[]]$Preferred)
$script:picked = @()
function Test-PortFree {
param([int]$Port)
if ($script:picked -contains $Port) { return $false }
try {
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, $Port)
$listener.Start()
$listener.Stop()
return $true
} catch {
return $false
}
}
function Get-RandomFreePort {
while ($true) {
$port = Get-Random -Minimum 20000 -Maximum 50000
if (Test-PortFree $port) { return $port }
}
}
foreach ($p in $Preferred) {
if (Test-PortFree $p) {
$script:picked += $p
} else {
$script:picked += Get-RandomFreePort
}
}
foreach ($p in $script:picked) {
[Console]::Out.Write("$p`n")
}
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Prints one free TCP port per preferred port given as an argument.
#
# For each argument, emits that port if it's free; otherwise emits a random
# free port in 20000-49999. Probes via bash's /dev/tcp pseudo-device (connect
# failure = nobody listening). Tracks picks within this run so outputs are
# guaranteed distinct from each other.
set -euo pipefail
declare -a picked=()
is_free() {
local port=$1
for p in ${picked[@]+"${picked[@]}"}; do
if [ "$p" = "$port" ]; then return 1; fi
done
if (exec 3<>"/dev/tcp/127.0.0.1/$port") >/dev/null 2>&1; then
return 1
fi
return 0
}
random_free_port() {
while true; do
local port=$((RANDOM % 30000 + 20000))
if is_free "$port"; then
echo "$port"
return
fi
done
}
for preferred in "$@"; do
if is_free "$preferred"; then
picked+=("$preferred")
else
picked+=("$(random_free_port)")
fi
done
for p in "${picked[@]}"; do
echo "$p"
done