Add an ns1 test-and-deploy workflow for the Go MCP server.
scripts/deploy-138.sh tests with Go 1.26.9, swaps the live binary, and rolls back if port 8000 stops answering. Port 0 in the embedded NATS listener now picks an ephemeral port so the test can run while 4222 is already taken.
This commit is contained in:
parent
deb0e251de
commit
dc39095694
5 changed files with 162 additions and 1 deletions
24
.forgejo/workflows/test-and-deploy.yml
Normal file
24
.forgejo/workflows/test-and-deploy.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
name: test-and-deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: 138
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Unit tests
|
||||
run: bash scripts/test-138.sh
|
||||
|
||||
deploy-138:
|
||||
needs: test
|
||||
if: success() && github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
||||
runs-on: 138
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Deploy with automatic health rollback
|
||||
run: bash scripts/deploy-138.sh
|
||||
|
|
@ -22,7 +22,7 @@ cd verae-mcp-timestamping-server-go
|
|||
go build -o bin/verae-mcp-timestamping-server ./cmd/verae-mcp-timestamping-server
|
||||
```
|
||||
|
||||
Requires Go 1.26+. Design: `docs/superpowers/specs/2026-09-29-go-mcp-timestamping-server-design.md`. Shadow systemd unit (not installed by this build): `deploy/verae-mcp-timestamping-go.service`.
|
||||
Requires Go 1.26+. Design: `docs/superpowers/specs/2026-09-29-go-mcp-timestamping-server-design.md`. The ns1 unit `verae-mcp-timestamping.service` runs this binary from `/opt/verae/verae-mcp-timestamping-server-go/bin`. `.forgejo/workflows/test-and-deploy.yml` tests on the `138` runner and `scripts/deploy-138.sh` swaps that binary, with a probe of `http://127.0.0.1:8000/mcp` and rollback to the previous file.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
|||
|
|
@ -119,5 +119,15 @@ func splitHostPort(listen string) (string, int, error) {
|
|||
if host == "" {
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
// nats-server treats port 0 as its default (4222), which is already taken
|
||||
// on ns1. Bind an ephemeral port and hand that number to the server.
|
||||
if port == 0 {
|
||||
ln, err := net.Listen("tcp", net.JoinHostPort(host, "0"))
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("embednats: ephemeral listen: %w", err)
|
||||
}
|
||||
port = ln.Addr().(*net.TCPAddr).Port
|
||||
ln.Close()
|
||||
}
|
||||
return host, port, nil
|
||||
}
|
||||
|
|
|
|||
122
scripts/deploy-138.sh
Executable file
122
scripts/deploy-138.sh
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env bash
|
||||
# Test, build, and swap the Go MCP binary on ns1.
|
||||
# Does not restart verae-timestamping-svc or forgejo-runner, and does not read secret files.
|
||||
set -euo pipefail
|
||||
|
||||
LOCK="${LOCK:-/tmp/verae-mcp-go-deploy.lock}"
|
||||
DEST="${DEST:-/opt/verae/verae-mcp-timestamping-server-go/bin/verae-mcp-timestamping-server}"
|
||||
SERVICE="${SERVICE:-verae-mcp-timestamping.service}"
|
||||
PROBE="${PROBE:-http://127.0.0.1:8000/mcp}"
|
||||
GO_ROOT="${GO_ROOT:-/usr/local/lib/go1.26.9}"
|
||||
GO_TARBALL="${GO_TARBALL:-go1.26.9.linux-amd64.tar.gz}"
|
||||
GO_SHA256="${GO_SHA256:-42d158b4d8f7b61ac0a830567c940a86098fb7aac52e467a5ebec03ef5cc2f8d}"
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
|
||||
mkdir -p "$(dirname "$LOCK")"
|
||||
exec 9>"$LOCK"
|
||||
if ! flock -n 9; then
|
||||
echo "another mcp deploy holds the lock" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ensure_go() {
|
||||
if [[ -x "$GO_ROOT/bin/go" ]] && "$GO_ROOT/bin/go" version | grep -q 'go1.26.9 '; then
|
||||
export PATH="$GO_ROOT/bin:$PATH"
|
||||
return
|
||||
fi
|
||||
local tmp
|
||||
tmp="$(mktemp -d)"
|
||||
curl -fsSL -o "$tmp/go.tgz" "https://go.dev/dl/${GO_TARBALL}"
|
||||
echo "${GO_SHA256} ${tmp}/go.tgz" | sha256sum -c -
|
||||
tar -C "$tmp" -xzf "$tmp/go.tgz"
|
||||
sudo rm -rf "$GO_ROOT"
|
||||
sudo mv "$tmp/go" "$GO_ROOT"
|
||||
rm -rf "$tmp"
|
||||
export PATH="$GO_ROOT/bin:$PATH"
|
||||
}
|
||||
|
||||
probe_ok() {
|
||||
local code
|
||||
code="$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$PROBE" || true)"
|
||||
[[ -n "$code" && "$code" != "000" ]]
|
||||
}
|
||||
|
||||
wait_probe() {
|
||||
local i
|
||||
for i in 1 2 3 4 5 6 7 8; do
|
||||
if probe_ok; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
swap_binary() {
|
||||
local src="$1"
|
||||
sudo systemctl stop "$SERVICE" || true
|
||||
local n=0
|
||||
while (( n < 5 )); do
|
||||
if sudo cp "$src" "$DEST"; then
|
||||
sudo chown verae-mcp:verae-mcp "$DEST"
|
||||
sudo chmod 755 "$DEST"
|
||||
sudo systemctl start "$SERVICE"
|
||||
return 0
|
||||
fi
|
||||
n=$((n + 1))
|
||||
sleep 1
|
||||
sudo systemctl stop "$SERVICE" || true
|
||||
done
|
||||
echo "could not replace $DEST" >&2
|
||||
sudo systemctl start "$SERVICE" || true
|
||||
return 1
|
||||
}
|
||||
|
||||
rollback() {
|
||||
local latest
|
||||
latest="$(ls -1t "${DEST}.bak-"* 2>/dev/null | head -1 || true)"
|
||||
if [[ -z "$latest" ]]; then
|
||||
echo "no backup to roll back to" >&2
|
||||
sudo systemctl start "$SERVICE" || true
|
||||
exit 1
|
||||
fi
|
||||
swap_binary "$latest"
|
||||
if wait_probe; then
|
||||
echo "rolled back to $latest (probe ok)"
|
||||
return 0
|
||||
fi
|
||||
echo "rollback probe still failing" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--rollback" ]]; then
|
||||
rollback
|
||||
exit $?
|
||||
fi
|
||||
|
||||
ensure_go
|
||||
cd "$ROOT"
|
||||
go test ./... -count=1
|
||||
go build -o /tmp/verae-mcp-timestamping-server-new ./cmd/verae-mcp-timestamping-server
|
||||
if ! grep -a -q 'verae-meta-git/1' /tmp/verae-mcp-timestamping-server-new; then
|
||||
echo "built binary is missing verae-meta-git/1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "--test-only" ]]; then
|
||||
echo "tests ok"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ts="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
sudo cp -a "$DEST" "${DEST}.bak-${ts}"
|
||||
if ! swap_binary /tmp/verae-mcp-timestamping-server-new; then
|
||||
rollback || true
|
||||
exit 1
|
||||
fi
|
||||
if ! wait_probe; then
|
||||
echo "new binary failed probe; rolling back" >&2
|
||||
rollback || true
|
||||
exit 1
|
||||
fi
|
||||
echo "deployed ${ts} probe ok"
|
||||
5
scripts/test-138.sh
Executable file
5
scripts/test-138.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Unit-test the Go MCP server with Go 1.26. Does not restart a service.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
exec bash "$ROOT/scripts/deploy-138.sh" --test-only
|
||||
Loading…
Reference in a new issue