3737 required : false
3838 default : ' '
3939 worker_runtime :
40- description : ' Worker runtime to use'
40+ description : ' Worker runtime to use (both = run openclaw and copaw in parallel) '
4141 required : false
4242 type : choice
4343 options :
44+ - both
4445 - openclaw
4546 - copaw
46- default : ' openclaw '
47+ default : ' both '
4748 model :
4849 description : ' LLM model to use'
4950 required : false
5051 default : ' qwen3.5-plus'
5152
5253env :
53- # Tests that do not require a GitHub token, split into two shards for parallel execution
54+ # Tests that do not require a GitHub token, split into four shards for parallel execution
5455 # Shard A: LLM interaction tests (sequential dependency: 02 creates alice → 03-06 use alice)
55- # Shard B: Controller/CR tests (independent, no cross-test dependencies)
56- SHARD_A_TESTS : " 01 02 03 04 05 06 100"
57- SHARD_B_TESTS : " 14 15 17 18 19 20"
58- NON_GITHUB_TESTS : " 01 02 03 04 05 06 14 15 17 18 19 20 100"
56+ # Shard B: LLM interaction tests 2 (task assignment with LLM)
57+ # Shard C: Controller/CR tests (independent, no cross-test dependencies)
58+ # Shard D: Controller/CR tests 2 (team project DAG)
59+ SHARD_A_TESTS : " 01 02 03 04 05 06"
60+ SHARD_B_TESTS : " 14"
61+ SHARD_C_TESTS : " 15 17 18 19 20 100"
62+ SHARD_D_TESTS : " 21"
63+ NON_GITHUB_TESTS : " 01 02 03 04 05 06 14 15 17 18 19 20 21 100"
5964
6065jobs :
61- # Build all images once, shared across test shards
62- build :
66+ # Step 1: Build the shared base image (hiclaw-controller)
67+ build-base :
6368 runs-on : ubuntu-latest
64- timeout-minutes : 30
69+ timeout-minutes : 15
6570 steps :
6671 - name : Free Up Disk Space
6772 uses : jlumbroso/free-disk-space@main
@@ -82,34 +87,80 @@ jobs:
8287 - name : Set up Docker Buildx
8388 uses : docker/setup-buildx-action@v3
8489
85- - name : Build images
86- env :
87- HICLAW_MANAGER_RUNTIME : ${{ inputs.worker_runtime || 'openclaw' }}
90+ - name : Build hiclaw-controller
91+ run : make build-hiclaw-controller DOCKER_BUILD_ARGS="--build-arg APT_MIRROR="
92+
93+ - name : Save image
8894 run : |
89- if [ "${HICLAW_MANAGER_RUNTIME}" = "copaw" ]; then
90- make build-embedded build-manager-copaw build-worker build-copaw-worker \
91- DOCKER_BUILD_ARGS="--build-arg APT_MIRROR="
92- else
93- make build-embedded build-manager build-worker build-copaw-worker \
94- DOCKER_BUILD_ARGS="--build-arg APT_MIRROR="
95- fi
95+ docker save hiclaw/hiclaw-controller:latest | gzip > /tmp/hiclaw-controller.tar.gz
96+
97+ - name : Upload image
98+ uses : actions/upload-artifact@v4
99+ with :
100+ name : image-controller
101+ path : /tmp/hiclaw-controller.tar.gz
102+ retention-days : 1
103+
104+ # Step 2: Build downstream images in parallel (all depend on hiclaw-controller)
105+ build-images :
106+ needs : build-base
107+ runs-on : ubuntu-latest
108+ timeout-minutes : 20
109+ strategy :
110+ fail-fast : false
111+ matrix :
112+ target : [embedded, manager, manager-copaw, worker, copaw-worker]
113+ steps :
114+ - name : Free Up Disk Space
115+ uses : jlumbroso/free-disk-space@main
116+ with :
117+ tool-cache : false
118+ android : true
119+ dotnet : true
120+ haskell : true
121+ large-packages : true
122+ swap-storage : true
96123
97- - name : Save images
124+ - name : Checkout code
125+ uses : actions/checkout@v4
126+ with :
127+ ref : ${{ github.event.pull_request.head.sha || github.sha }}
128+ repository : ${{ github.event.pull_request.head.repo.full_name || github.repository }}
129+
130+ - name : Set up Docker Buildx
131+ uses : docker/setup-buildx-action@v3
132+
133+ - name : Download controller image
134+ uses : actions/download-artifact@v4
135+ with :
136+ name : image-controller
137+ path : /tmp
138+
139+ - name : Load controller image
140+ run : gunzip -c /tmp/hiclaw-controller.tar.gz | docker load
141+
142+ - name : Build image
143+ run : make build-${{ matrix.target }} DOCKER_BUILD_ARGS="--build-arg APT_MIRROR="
144+
145+ - name : Save image
98146 run : |
99147 docker save \
100- $(docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^hiclaw/' | grep -v '<none>') \
101- | gzip > /tmp/hiclaw-images .tar.gz
148+ $(docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^hiclaw/' | grep -v '<none>' | grep -v 'hiclaw-controller' ) \
149+ | gzip > /tmp/hiclaw-${{ matrix.target }} .tar.gz
102150
103- - name : Upload images artifact
151+ - name : Upload image
104152 uses : actions/upload-artifact@v4
105153 with :
106- name : hiclaw-images
107- path : /tmp/hiclaw-images .tar.gz
154+ name : image-${{ matrix.target }}
155+ path : /tmp/hiclaw-${{ matrix.target }} .tar.gz
108156 retention-days : 1
109157
110- # Run test shards in parallel, each on its own runner with isolated cluster
158+ # Step 3: Run test shards in parallel, each on its own runner with isolated cluster
111159 integration-tests :
112- needs : build
160+ needs : build-images
161+ if : >-
162+ inputs.worker_runtime == '' || inputs.worker_runtime == 'both'
163+ || inputs.worker_runtime == matrix.runtime
113164 runs-on : ubuntu-latest
114165 timeout-minutes : 90
115166 permissions :
@@ -122,8 +173,28 @@ jobs:
122173 include :
123174 - shard : llm-interaction
124175 filter_env : SHARD_A_TESTS
176+ runtime : openclaw
177+ - shard : llm-interaction-2
178+ filter_env : SHARD_B_TESTS
179+ runtime : openclaw
125180 - shard : controller-cr
181+ filter_env : SHARD_C_TESTS
182+ runtime : openclaw
183+ - shard : controller-cr-2
184+ filter_env : SHARD_D_TESTS
185+ runtime : openclaw
186+ - shard : llm-interaction
187+ filter_env : SHARD_A_TESTS
188+ runtime : copaw
189+ - shard : llm-interaction-2
126190 filter_env : SHARD_B_TESTS
191+ runtime : copaw
192+ - shard : controller-cr
193+ filter_env : SHARD_C_TESTS
194+ runtime : copaw
195+ - shard : controller-cr-2
196+ filter_env : SHARD_D_TESTS
197+ runtime : copaw
127198
128199 steps :
129200 - name : Free Up Disk Space
@@ -142,14 +213,17 @@ jobs:
142213 ref : ${{ github.event.pull_request.head.sha || github.sha }}
143214 repository : ${{ github.event.pull_request.head.repo.full_name || github.repository }}
144215
145- - name : Download pre-built images
216+ - name : Download all images
146217 uses : actions/download-artifact@v4
147218 with :
148- name : hiclaw-images
149- path : /tmp
219+ pattern : image-*
220+ path : /tmp/images
150221
151222 - name : Load images
152- run : gunzip -c /tmp/hiclaw-images.tar.gz | docker load
223+ run : |
224+ for f in /tmp/images/image-*/*.tar.gz; do
225+ gunzip -c "$f" | docker load
226+ done
153227
154228 - name : Install dependencies
155229 run : sudo apt-get update && sudo apt-get install -y jq curl unzip
@@ -160,7 +234,7 @@ jobs:
160234 HICLAW_LLM_API_KEY : ${{ secrets.HICLAW_LLM_API_KEY }}
161235 HICLAW_LLM_PROVIDER : qwen
162236 HICLAW_DEFAULT_MODEL : ${{ inputs.model || 'qwen3.5-plus' }}
163- HICLAW_MANAGER_RUNTIME : ${{ inputs.worker_runtime || 'openclaw' }}
237+ HICLAW_MANAGER_RUNTIME : ${{ matrix.runtime }}
164238 run : |
165239 FILTER="${{ github.event.inputs.test_filter }}"
166240 if [ -z "$FILTER" ]; then
@@ -174,7 +248,7 @@ jobs:
174248 # ============================================================
175249
176250 - name : Download latest release baseline
177- if : github.event_name == 'pull_request_target' && matrix.shard == 'llm-interaction'
251+ if : github.event_name == 'pull_request_target' && matrix.shard == 'llm-interaction' && matrix.runtime == 'openclaw'
178252 continue-on-error : true
179253 run : |
180254 mkdir -p baseline-metrics
@@ -194,7 +268,7 @@ jobs:
194268 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
195269
196270 - name : Generate metrics comparison and post PR comment
197- if : github.event_name == 'pull_request_target' && matrix.shard == 'llm-interaction'
271+ if : github.event_name == 'pull_request_target' && matrix.shard == 'llm-interaction' && matrix.runtime == 'openclaw'
198272 env :
199273 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
200274 run : |
@@ -281,7 +355,7 @@ jobs:
281355 DEBUG_TAIL=$(find "$DEBUG_DIR" -name "*.log" -exec tail -20 {} + 2>/dev/null | tail -80)
282356 fi
283357
284- BODY="## ❌ Integration Tests Failed (${{ matrix.shard }})
358+ BODY="## ❌ Integration Tests Failed (${{ matrix.shard }} / ${{ matrix.runtime }} )
285359
286360 **Commit:** ${{ github.event.pull_request.head.sha }}
287361 **Workflow run:** [#${{ github.run_number }}](${ARTIFACT_URL})
@@ -309,7 +383,7 @@ jobs:
309383
310384 # Update or create comment
311385 EXISTING=$(gh api "repos/$REPO/issues/$PR_NUM/comments" \
312- --jq '.[] | select(.body | startswith("## ❌ Integration Tests Failed (${{ matrix.shard }})")) | .id' | head -1)
386+ --jq '.[] | select(.body | startswith("## ❌ Integration Tests Failed (${{ matrix.shard }} / ${{ matrix.runtime }} )")) | .id' | head -1)
313387 if [ -n "$EXISTING" ]; then
314388 gh api --method PATCH "repos/$REPO/issues/comments/$EXISTING" -f body="$BODY"
315389 else
@@ -327,7 +401,7 @@ jobs:
327401 if : always()
328402 uses : actions/upload-artifact@v4
329403 with :
330- name : test-artifacts-${{ matrix.shard }}-${{ github.sha }}
404+ name : test-artifacts-${{ matrix.shard }}-${{ matrix.runtime }}-${{ github.sha }}
331405 path : test-artifacts/
332406 retention-days : 7
333407
@@ -336,7 +410,7 @@ jobs:
336410 # ============================================================
337411
338412 - name : Generate release baseline
339- if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction'
413+ if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction' && matrix.runtime == 'openclaw'
340414 run : |
341415 source tests/lib/agent-metrics.sh
342416 TEST_NAMES=$(echo "$NON_GITHUB_TESTS" | tr ' ' '\n' | while read n; do
@@ -348,7 +422,7 @@ jobs:
348422 cat metrics-baseline.json | jq '{totals: .totals, by_role: .by_role}'
349423
350424 - name : Upload baseline to release
351- if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction'
425+ if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction' && matrix.runtime == 'openclaw'
352426 env :
353427 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
354428 run : |
@@ -357,7 +431,7 @@ jobs:
357431 echo "✅ Baseline uploaded to release ${GITHUB_REF_NAME}"
358432
359433 - name : Upload debug log to release
360- if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction' && always()
434+ if : startsWith(github.ref, 'refs/tags/v') && matrix.shard == 'llm-interaction' && matrix.runtime == 'openclaw' && always()
361435 continue-on-error : true
362436 env :
363437 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
@@ -379,7 +453,7 @@ jobs:
379453 echo "### Integration Test Summary" >> $GITHUB_STEP_SUMMARY
380454 echo "- Shard: \`${{ matrix.shard }}\`" >> $GITHUB_STEP_SUMMARY
381455 echo "- Tests: \`${{ env[matrix.filter_env] }}\`" >> $GITHUB_STEP_SUMMARY
382- echo "- Worker Runtime: \`${{ inputs.worker_runtime || 'openclaw' }}\`" >> $GITHUB_STEP_SUMMARY
456+ echo "- Worker Runtime: \`${{ matrix.runtime }}\`" >> $GITHUB_STEP_SUMMARY
383457 echo "- Model: \`${{ inputs.model || 'qwen3.5-plus' }}\`" >> $GITHUB_STEP_SUMMARY
384458 echo "- Install Mode: embedded (make test-embedded)" >> $GITHUB_STEP_SUMMARY
385459
0 commit comments