Skip to content

Commit e607a8a

Browse files
committed
Add CI smoke coverage on Linux and macOS
1 parent 919493a commit e607a8a

6 files changed

Lines changed: 128 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ permissions:
1111

1212
jobs:
1313
rust:
14-
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
os: [ubuntu-latest, macos-latest]
18+
runs-on: ${{ matrix.os }}
1519
steps:
1620
- name: Check out repository
1721
uses: actions/checkout@v4
@@ -32,3 +36,6 @@ jobs:
3236

3337
- name: Run clippy
3438
run: cargo clippy --all-targets --all-features -- -D warnings
39+
40+
- name: Run runtime smoke test
41+
run: ./scripts/ci-smoke.sh

examples/blog/devloop.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ state_key = "current_browser_path"
6060
state_key = "current_browser_path"
6161
workflow = "publish_post_url"
6262
pattern = "^/(|posts/[a-z0-9-]+)$"
63-
observe = { workflow = "publish_post_url", interval_ms = 1000 }
6463

6564
[workflow.publish_post_url]
6665
steps = [

fixtures/ci-smoke/devloop.toml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
root = "."
2+
debounce_ms = 100
3+
state_file = "./.devloop/state.json"
4+
startup_workflows = ["startup"]
5+
6+
[watch.content]
7+
paths = ["watched.txt"]
8+
workflow = "content"
9+
10+
[process.server]
11+
command = ["python3", "-m", "http.server", "18081", "--bind", "127.0.0.1"]
12+
cwd = "."
13+
autostart = false
14+
restart = "never"
15+
output = { inherit = false }
16+
17+
[process.server.readiness]
18+
kind = "http"
19+
url = "http://127.0.0.1:18081/"
20+
interval_ms = 100
21+
timeout_ms = 5000
22+
23+
[hook.current_value]
24+
command = ["./scripts/read-watched.sh"]
25+
cwd = "."
26+
capture = "text"
27+
state_key = "current_value"
28+
output = { inherit = false }
29+
30+
[workflow.startup]
31+
steps = [
32+
{ action = "start_process", process = "server" },
33+
{ action = "wait_for_process", process = "server" },
34+
{ action = "run_hook", hook = "current_value" },
35+
{ action = "log", message = "startup value: {{current_value}}" },
36+
]
37+
38+
[workflow.content]
39+
steps = [
40+
{ action = "run_hook", hook = "current_value" },
41+
{ action = "write_state", key = "current_url", value = "http://127.0.0.1:18081/{{current_value}}" },
42+
{ action = "log", message = "changed value: {{current_value}}" },
43+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
tr -d '\r' < watched.txt | head -n 1

fixtures/ci-smoke/watched.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
initial

scripts/ci-smoke.sh

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5+
fixture_src="${repo_root}/fixtures/ci-smoke"
6+
tmp_dir="$(mktemp -d)"
7+
cleanup() {
8+
if [[ -n "${devloop_pid:-}" ]] && kill -0 "${devloop_pid}" 2>/dev/null; then
9+
kill -INT "${devloop_pid}" 2>/dev/null || true
10+
wait "${devloop_pid}" || true
11+
fi
12+
rm -rf "${tmp_dir}"
13+
}
14+
trap cleanup EXIT
15+
16+
cp -R "${fixture_src}/." "${tmp_dir}/"
17+
chmod +x "${tmp_dir}/scripts/read-watched.sh"
18+
19+
log_path="${tmp_dir}/devloop.log"
20+
state_path="${tmp_dir}/.devloop/state.json"
21+
devloop_bin="${repo_root}/target/debug/devloop"
22+
23+
if [[ ! -x "${devloop_bin}" ]]; then
24+
(cd "${repo_root}" && cargo build >/dev/null)
25+
fi
26+
27+
"${devloop_bin}" run --config "${tmp_dir}/devloop.toml" >"${log_path}" 2>&1 &
28+
devloop_pid=$!
29+
30+
python3 - "$state_path" <<'PY'
31+
import json
32+
import pathlib
33+
import sys
34+
import time
35+
36+
state_path = pathlib.Path(sys.argv[1])
37+
deadline = time.time() + 15
38+
while time.time() < deadline:
39+
if state_path.exists():
40+
data = json.loads(state_path.read_text())
41+
if data.get("current_value") == "initial":
42+
sys.exit(0)
43+
time.sleep(0.1)
44+
raise SystemExit("timed out waiting for startup state")
45+
PY
46+
47+
printf 'updated\n' > "${tmp_dir}/watched.txt"
48+
49+
python3 - "$state_path" "$log_path" <<'PY'
50+
import json
51+
import pathlib
52+
import sys
53+
import time
54+
55+
state_path = pathlib.Path(sys.argv[1])
56+
log_path = pathlib.Path(sys.argv[2])
57+
deadline = time.time() + 15
58+
while time.time() < deadline:
59+
if state_path.exists():
60+
data = json.loads(state_path.read_text())
61+
if (
62+
data.get("current_value") == "updated"
63+
and data.get("current_url") == "http://127.0.0.1:18081/updated"
64+
):
65+
if "changed value: updated" in log_path.read_text():
66+
sys.exit(0)
67+
time.sleep(0.1)
68+
raise SystemExit("timed out waiting for changed state")
69+
PY
70+
71+
kill -INT "${devloop_pid}"
72+
wait "${devloop_pid}"

0 commit comments

Comments
 (0)