Skip to content

Commit 5e353cd

Browse files
MDA2AVclaude
andcommitted
Sequential probe — one server at a time on port 8080
Replace docker-compose with convention-based discovery from src/Servers/*/probe.json. All servers now listen on port 8080 and are built/run/probed/killed sequentially, eliminating port allocation and simplifying the contributor experience to Dockerfile + probe.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ab5a968 commit 5e353cd

27 files changed

Lines changed: 76 additions & 203 deletions

File tree

.github/workflows/probe.yml

Lines changed: 46 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,22 @@ jobs:
2828
- name: Discover servers
2929
id: discover
3030
run: |
31-
SERVERS=$(docker compose config --format json | jq -c '
32-
[.services | to_entries[] |
33-
select(.value.labels["probe.port"] != null) |
34-
{
35-
service: .key,
36-
port: (.value.labels["probe.port"] | tonumber),
37-
name: .value.labels["probe.name"],
38-
dir: (.value.build.dockerfile | capture("src/Servers/(?<d>[^/]+)/Dockerfile").d)
39-
}
40-
] | sort_by(.port)')
31+
SERVERS='[]'
32+
for f in src/Servers/*/probe.json; do
33+
dir=$(basename "$(dirname "$f")")
34+
name=$(jq -r .name "$f")
35+
SERVERS=$(echo "$SERVERS" | jq -c --arg d "$dir" --arg n "$name" '. + [{"dir": $d, "name": $n}]')
36+
done
4137
echo "servers=$SERVERS" >> "$GITHUB_OUTPUT"
42-
ALL_SERVICES=$(echo "$SERVERS" | jq -r '.[].service' | tr '\n' ' ' | sed 's/ $//')
43-
echo "all_services=$ALL_SERVICES" >> "$GITHUB_OUTPUT"
44-
echo "Discovered: $ALL_SERVICES"
38+
echo "Discovered: $(echo "$SERVERS" | jq -r '.[].name' | tr '\n' ', ')"
4539
4640
- name: Detect changes
4741
id: changes
4842
run: |
4943
SERVERS='${{ steps.discover.outputs.servers }}'
50-
ALL_SERVICES="${{ steps.discover.outputs.all_services }}"
5144
5245
set_all() {
53-
echo "affected=$ALL_SERVICES" >> "$GITHUB_OUTPUT"
46+
echo "servers=$SERVERS" >> "$GITHUB_OUTPUT"
5447
}
5548
5649
# workflow_dispatch always runs everything
@@ -62,94 +55,78 @@ jobs:
6255
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
6356
6457
# Global triggers → run all
65-
if echo "$CHANGED" | grep -qE '^(src/Http11Probe/|src/Http11Probe\.Cli/|Directory\.Build\.props|docker-compose\.yml|\.dockerignore|\.github/workflows/probe\.yml)'; then
58+
if echo "$CHANGED" | grep -qE '^(src/Http11Probe/|src/Http11Probe\.Cli/|Directory\.Build\.props|\.dockerignore|\.github/workflows/probe\.yml)'; then
6659
set_all
6760
exit 0
6861
fi
6962
70-
AFFECTED=""
63+
AFFECTED='[]'
7164
for row in $(echo "$SERVERS" | jq -r '.[] | @base64'); do
72-
svc=$(echo "$row" | base64 -d | jq -r '.service')
7365
dir=$(echo "$row" | base64 -d | jq -r '.dir')
66+
name=$(echo "$row" | base64 -d | jq -r '.name')
7467
if echo "$CHANGED" | grep -q "^src/Servers/${dir}/"; then
75-
AFFECTED="$AFFECTED $svc"
68+
AFFECTED=$(echo "$AFFECTED" | jq -c --arg d "$dir" --arg n "$name" '. + [{"dir": $d, "name": $n}]')
7669
fi
7770
done
7871
79-
echo "affected=${AFFECTED# }" >> "$GITHUB_OUTPUT"
72+
echo "servers=$AFFECTED" >> "$GITHUB_OUTPUT"
8073
8174
- name: Setup .NET
82-
if: steps.changes.outputs.affected != ''
75+
if: steps.changes.outputs.servers != '[]'
8376
uses: actions/setup-dotnet@v4
8477
with:
8578
dotnet-version: '10.0'
8679

8780
- name: Build probe CLI
88-
if: steps.changes.outputs.affected != ''
81+
if: steps.changes.outputs.servers != '[]'
8982
run: dotnet build Http11Probe.slnx -c Release
9083

91-
# ── Start only affected servers via Docker Compose ──────────────
92-
93-
- name: Start servers
94-
if: steps.changes.outputs.affected != ''
95-
run: docker compose up -d --build ${{ steps.changes.outputs.affected }}
84+
# ── Build / Run / Probe / Kill — one server at a time ──────────
9685

97-
- name: Wait for servers
98-
if: steps.changes.outputs.affected != ''
86+
- name: Probe servers
87+
if: steps.changes.outputs.servers != '[]'
9988
run: |
100-
SERVERS='${{ steps.discover.outputs.servers }}'
101-
for svc in ${{ steps.changes.outputs.affected }}; do
102-
port=$(echo "$SERVERS" | jq -r --arg s "$svc" '.[] | select(.service == $s) | .port')
89+
SERVERS='${{ steps.changes.outputs.servers }}'
90+
PROBE_PORT=8080
91+
92+
for row in $(echo "$SERVERS" | jq -r '.[] | @base64'); do
93+
dir=$(echo "$row" | base64 -d | jq -r '.dir')
94+
name=$(echo "$row" | base64 -d | jq -r '.name')
95+
96+
echo "::group::$name"
97+
98+
# Build
99+
docker build -t "probe-$dir" -f "src/Servers/$dir/Dockerfile" .
100+
101+
# Run
102+
docker run -d --name probe-target --network host "probe-$dir"
103+
104+
# Wait
103105
for i in $(seq 1 30); do
104-
if curl -sf "http://localhost:${port}/" > /dev/null 2>&1; then
105-
echo "$svc ready on port $port"; break
106-
fi
106+
curl -sf "http://localhost:${PROBE_PORT}/" > /dev/null 2>&1 && break
107107
sleep 1
108108
done
109-
if [ "$i" = "30" ]; then
110-
echo "::warning::$svc did not start in time (port $port)"
111-
fi
112-
done
113109
114-
- name: Verify servers
115-
if: steps.changes.outputs.affected != ''
116-
run: |
117-
SERVERS='${{ steps.discover.outputs.servers }}'
118-
echo "── Listening ports ──"
119-
ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null || true
120-
echo "── Health checks ──"
121-
for svc in ${{ steps.changes.outputs.affected }}; do
122-
port=$(echo "$SERVERS" | jq -r --arg s "$svc" '.[] | select(.service == $s) | .port')
123-
curl -sf "http://localhost:${port}/" && echo " $svc OK (port $port)" || echo " $svc FAIL (port $port)"
124-
done
110+
# Probe
111+
dotnet run --no-build -c Release --project src/Http11Probe.Cli -- \
112+
--host localhost --port "$PROBE_PORT" --output "probe-${dir}.json" || true
125113
126-
# ── Run probe against each affected server ─────────────────────
114+
# Kill
115+
docker stop probe-target && docker rm probe-target
127116
128-
- name: Probe servers
129-
if: steps.changes.outputs.affected != ''
130-
run: |
131-
SERVERS='${{ steps.discover.outputs.servers }}'
132-
for svc in ${{ steps.changes.outputs.affected }}; do
133-
port=$(echo "$SERVERS" | jq -r --arg s "$svc" '.[] | select(.service == $s) | .port')
134-
name=$(echo "$SERVERS" | jq -r --arg s "$svc" '.[] | select(.service == $s) | .name')
135-
echo "::group::Probing $name ($svc) on port $port"
136-
dotnet run --no-build -c Release --project src/Http11Probe.Cli -- \
137-
--host localhost --port "$port" --output "probe-${svc}.json" || true
138117
echo "::endgroup::"
139118
done
140119
141-
# ── Stop all servers ───────────────────────────────────────────
142-
143-
- name: Stop servers
120+
- name: Cleanup
144121
if: always()
145-
run: docker compose down
122+
run: docker rm -f probe-target 2>/dev/null || true
146123

147124
# ── Process results ────────────────────────────────────────────
148125

149126
- name: Process results
150-
if: steps.changes.outputs.affected != ''
127+
if: steps.changes.outputs.servers != '[]'
151128
env:
152-
PROBE_SERVERS: ${{ steps.discover.outputs.servers }}
129+
PROBE_SERVERS: ${{ steps.changes.outputs.servers }}
153130
run: |
154131
python3 << 'PYEOF'
155132
import json, sys, os, subprocess, pathlib
@@ -447,7 +424,7 @@ jobs:
447424
448425
# ── Process each server ──────────────────────────────────────
449426
servers_config = json.loads(os.environ['PROBE_SERVERS'])
450-
SERVERS = [(s['name'], f"probe-{s['service']}.json") for s in servers_config]
427+
SERVERS = [(s['name'], f"probe-{s['dir']}.json") for s in servers_config]
451428
452429
commit_id = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode().strip()
453430
commit_msg = subprocess.check_output(['git', 'log', '-1', '--format=%s']).decode().strip()
@@ -555,7 +532,7 @@ jobs:
555532
path: probe-*.json
556533

557534
- name: Comment on PR
558-
if: github.event_name == 'pull_request' && steps.changes.outputs.affected != ''
535+
if: github.event_name == 'pull_request' && steps.changes.outputs.servers != '[]'
559536
run: |
560537
COMMENT_ID=$(gh api repos/${{ github.repository }}/issues/${{ github.event.number }}/comments \
561538
--jq '.[] | select(.body | contains("<!-- http11probe-results -->")) | .id' | head -1)

docker-compose.yml

Lines changed: 0 additions & 109 deletions
This file was deleted.

docs/content/_index.md

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,23 @@ Http11Probe is designed so anyone can contribute their HTTP server and get compl
5252

5353
<div style="height:24px"></div>
5454

55-
**1. Write a minimal server** — Create a directory under `src/Servers/YourServer/` with a simple HTTP server that returns `200 OK` on `GET /`. Any language, any framework.
55+
**1. Write a minimal server** — Create a directory under `src/Servers/YourServer/` with a simple HTTP server that listens on **port 8080** and returns `200 OK` on `GET /`. Any language, any framework.
5656

5757
<div style="height:16px"></div>
5858

59-
**2. Add a Dockerfile** — Build and run your server. It will use `network_mode: host` so it binds directly to the host network.
59+
**2. Add a Dockerfile** — Build and run your server. It will run with `--network host`.
6060

6161
<div style="height:16px"></div>
6262

63-
**3. Add to docker-compose.yml**Add a service entry with two labels. That's the only configuration needed:
63+
**3. Add a `probe.json`**One file, one field:
6464

6565
<div style="height:12px"></div>
6666

67-
```yaml
68-
yourserver:
69-
build:
70-
context: .
71-
dockerfile: src/Servers/YourServer/Dockerfile
72-
network_mode: host
73-
labels:
74-
probe.port: "9020"
75-
probe.name: "Your Server"
67+
```json
68+
{"name": "Your Server"}
7669
```
7770

7871
<div style="height:24px"></div>
7972

80-
The CI pipeline auto-discovers servers from `docker-compose.yml` labels. No workflow edits, no test changes, no config files. Open a PR and the probe runs automatically.
73+
The CI pipeline auto-discovers servers from `src/Servers/*/probe.json`. No workflow edits, no test changes, no config files. Open a PR and the probe runs automatically.
8174

src/Servers/ApacheServer/httpd-probe.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ServerRoot "/usr/local/apache2"
2-
Listen 9009
2+
Listen 8080
33

44
LoadModule mpm_event_module modules/mod_mpm_event.so
55
LoadModule dir_module modules/mod_dir.so
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name": "Apache"}

src/Servers/AspNetMinimal/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var builder = WebApplication.CreateBuilder(args);
22

3-
builder.WebHost.UseUrls("http://localhost:5099");
3+
builder.WebHost.UseUrls("http://localhost:8080");
44

55
var app = builder.Build();
66

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name": "Kestrel"}

src/Servers/CaddyServer/Caddyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
:9010 {
1+
:8080 {
22
respond "OK" 200
33
}

src/Servers/CaddyServer/probe.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name": "Caddy"}

src/Servers/ExpressServer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ WORKDIR /app
33
COPY src/Servers/ExpressServer/package.json .
44
RUN npm install --omit=dev
55
COPY src/Servers/ExpressServer/server.js .
6-
ENTRYPOINT ["node", "server.js", "9003"]
6+
ENTRYPOINT ["node", "server.js", "8080"]

0 commit comments

Comments
 (0)