Skip to content

Commit 4aa76be

Browse files
Merge branch 'main' into fix/workflow-monitor-oom
2 parents b1e4198 + cd1c35f commit 4aa76be

664 files changed

Lines changed: 51692 additions & 17404 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 199 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,39 @@ name: CI
22

33
on:
44
push:
5+
branches:
6+
- main
57
paths-ignore:
68
- "conductor-clients/**"
79
pull_request:
810
paths-ignore:
911
- "conductor-clients/**"
12+
workflow_dispatch:
13+
inputs:
14+
redis_es8:
15+
description: "Redis + Elasticsearch 8"
16+
type: boolean
17+
default: true
18+
postgres:
19+
description: "PostgreSQL"
20+
type: boolean
21+
default: false
22+
mysql:
23+
description: "MySQL"
24+
type: boolean
25+
default: false
26+
redis_os3:
27+
description: "Redis + OpenSearch 3"
28+
type: boolean
29+
default: false
30+
redis_es7:
31+
description: "Redis + Elasticsearch 7"
32+
type: boolean
33+
default: false
34+
cassandra_es7:
35+
description: "Cassandra + Elasticsearch 7"
36+
type: boolean
37+
default: false
1038

1139
jobs:
1240
build:
@@ -16,6 +44,11 @@ jobs:
1644
with:
1745
ref: ${{ github.event.pull_request.head.sha }}
1846
fetch-depth: 0
47+
- name: Free disk space
48+
run: |
49+
sudo rm -rf /usr/share/dotnet
50+
sudo rm -rf /usr/local/lib/android
51+
sudo rm -rf /opt/ghc
1952
- name: Gradle wrapper validation
2053
uses: gradle/wrapper-validation-action@v3
2154
- name: Set up Zulu JDK 21
@@ -44,7 +77,7 @@ jobs:
4477
id: docker-cache
4578
with:
4679
path: /tmp/docker-images-build.tar
47-
key: docker-build-v1
80+
key: docker-build-v2
4881
- name: Load cached Docker images
4982
if: steps.docker-cache.outputs.cache-hit == 'true'
5083
run: docker load -i /tmp/docker-images-build.tar || true
@@ -63,7 +96,18 @@ jobs:
6396
- name: Save Docker images for cache
6497
if: steps.docker-cache.outputs.cache-hit != 'true'
6598
run: |
66-
docker images --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>' | xargs -r docker save -o /tmp/docker-images-build.tar
99+
set -euo pipefail
100+
docker image prune -f
101+
mapfile -t images < <((docker images --format '{{.Repository}}:{{.Tag}}' \
102+
| grep -v '<none>' \
103+
| grep -E '(^|/)(elasticsearch|redis|postgres|mysql|mongo|cassandra)(:|/)|mockserver/mockserver|opensearchproject/opensearch|testcontainers/|orkesio/') || true)
104+
if [ "${#images[@]}" -eq 0 ]; then
105+
echo "No Testcontainers-related images to cache; writing empty tar for cache action."
106+
tar -cf /tmp/docker-images-build.tar --files-from /dev/null
107+
exit 0
108+
fi
109+
printf '%s\n' "${images[@]}"
110+
docker save -o /tmp/docker-images-build.tar "${images[@]}"
67111
- name: Generate aggregated coverage report
68112
if: always()
69113
run: ./gradlew jacocoAggregatedReport -x test || true
@@ -95,6 +139,11 @@ jobs:
95139
with:
96140
ref: ${{ github.event.pull_request.head.sha }}
97141
fetch-depth: 0
142+
- name: Free disk space
143+
run: |
144+
sudo rm -rf /usr/share/dotnet
145+
sudo rm -rf /usr/local/lib/android
146+
sudo rm -rf /opt/ghc
98147
- name: Set up Zulu JDK 21
99148
uses: actions/setup-java@v5
100149
with:
@@ -115,7 +164,7 @@ jobs:
115164
id: docker-cache
116165
with:
117166
path: /tmp/docker-images-test-harness.tar
118-
key: docker-test-harness-v1
167+
key: docker-test-harness-v2
119168
- name: Load cached Docker images
120169
if: steps.docker-cache.outputs.cache-hit == 'true'
121170
run: docker load -i /tmp/docker-images-test-harness.tar || true
@@ -125,7 +174,18 @@ jobs:
125174
- name: Save Docker images for cache
126175
if: steps.docker-cache.outputs.cache-hit != 'true'
127176
run: |
128-
docker images --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>' | xargs -r docker save -o /tmp/docker-images-test-harness.tar
177+
set -euo pipefail
178+
docker image prune -f
179+
mapfile -t images < <((docker images --format '{{.Repository}}:{{.Tag}}' \
180+
| grep -v '<none>' \
181+
| grep -E '(^|/)(elasticsearch|redis|postgres|mysql|mongo|cassandra)(:|/)|mockserver/mockserver|opensearchproject/opensearch|testcontainers/|orkesio/') || true)
182+
if [ "${#images[@]}" -eq 0 ]; then
183+
echo "No Testcontainers-related images to cache; writing empty tar for cache action."
184+
tar -cf /tmp/docker-images-test-harness.tar --files-from /dev/null
185+
exit 0
186+
fi
187+
printf '%s\n' "${images[@]}"
188+
docker save -o /tmp/docker-images-test-harness.tar "${images[@]}"
129189
- name: Publish Test Report
130190
uses: mikepenz/action-junit-report@v6
131191
if: always()
@@ -143,46 +203,158 @@ jobs:
143203
with:
144204
name: test-harness-coverage-report
145205
path: "test-harness/build/reports/jacoco"
206+
generate-e2e-matrix:
207+
runs-on: ubuntu-latest
208+
outputs:
209+
matrix: ${{ steps.set-matrix.outputs.matrix }}
210+
steps:
211+
- id: set-matrix
212+
shell: bash
213+
run: |
214+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
215+
items=""
216+
[ "${{ inputs.redis_es8 }}" = "true" ] && items="${items}{\"name\":\"redis-es8\",\"script\":\"./e2e/run_tests-es8.sh\"},"
217+
[ "${{ inputs.postgres }}" = "true" ] && items="${items}{\"name\":\"postgres\",\"script\":\"./e2e/run_tests-postgres.sh\"},"
218+
[ "${{ inputs.mysql }}" = "true" ] && items="${items}{\"name\":\"mysql\",\"script\":\"./e2e/run_tests-mysql.sh\"},"
219+
[ "${{ inputs.redis_os3 }}" = "true" ] && items="${items}{\"name\":\"redis-os3\",\"script\":\"./e2e/run_tests-redis-os3.sh\"},"
220+
[ "${{ inputs.redis_es7 }}" = "true" ] && items="${items}{\"name\":\"redis-es7\",\"script\":\"./e2e/run_tests-redis-es7.sh\"},"
221+
[ "${{ inputs.cassandra_es7 }}" = "true" ] && items="${items}{\"name\":\"cassandra-es7\",\"script\":\"./e2e/run_tests-cassandra-es7.sh\"},"
222+
items="${items%,}"
223+
echo "matrix={\"include\":[${items}]}" >> "$GITHUB_OUTPUT"
224+
else
225+
echo 'matrix={"include":[{"name":"redis-es8","script":"./e2e/run_tests-es8.sh"}]}' >> "$GITHUB_OUTPUT"
226+
fi
227+
228+
e2e:
229+
needs: generate-e2e-matrix
230+
if: ${{ needs.generate-e2e-matrix.outputs.matrix != '{"include":[]}' }}
231+
runs-on: ubuntu-latest
232+
strategy:
233+
fail-fast: false
234+
matrix: ${{ fromJson(needs.generate-e2e-matrix.outputs.matrix) }}
235+
steps:
236+
- uses: actions/checkout@v6
237+
with:
238+
ref: ${{ github.event.pull_request.head.sha }}
239+
fetch-depth: 0
240+
- name: Free disk space
241+
run: |
242+
sudo rm -rf /usr/share/dotnet
243+
sudo rm -rf /usr/local/lib/android
244+
sudo rm -rf /opt/ghc
245+
- name: Set up Zulu JDK 21
246+
uses: actions/setup-java@v5
247+
with:
248+
distribution: "zulu"
249+
java-version: "21"
250+
- name: Cache Gradle packages
251+
uses: actions/cache@v5
252+
with:
253+
path: |
254+
~/.gradle/caches
255+
~/.gradle/wrapper
256+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
257+
restore-keys: ${{ runner.os }}-gradle-
258+
- name: Run E2E tests (${{ matrix.name }})
259+
run: ${{ matrix.script }}
260+
- name: Publish Test Report
261+
uses: mikepenz/action-junit-report@v6
262+
if: always()
263+
with:
264+
report_paths: "e2e/build/test-results/test/TEST-*.xml"
265+
- name: Generate test summary table
266+
if: always()
267+
shell: python3 {0}
268+
run: |
269+
import os, glob, xml.etree.ElementTree as ET
270+
271+
xml_files = glob.glob("e2e/build/test-results/test/TEST-*.xml")
272+
rows = []
273+
totals = {"passed": 0, "failed": 0, "skipped": 0}
274+
275+
for f in sorted(xml_files):
276+
try:
277+
root = ET.parse(f).getroot()
278+
except ET.ParseError:
279+
continue
280+
for tc in root.iter("testcase"):
281+
name = tc.get("name", "?")
282+
classname = tc.get("classname", "").split(".")[-1]
283+
duration = float(tc.get("time", 0))
284+
if tc.find("skipped") is not None:
285+
status, totals["skipped"] = "⏭ skip", totals["skipped"] + 1
286+
elif tc.find("failure") is not None or tc.find("error") is not None:
287+
node = tc.find("failure") if tc.find("failure") is not None else tc.find("error")
288+
msg = (node.get("message") or "")[:120]
289+
status, totals["failed"] = f"❌ `{msg}`", totals["failed"] + 1
290+
else:
291+
status, totals["passed"] = "✅", totals["passed"] + 1
292+
rows.append((classname, name, f"{duration:.1f}s", status))
293+
294+
backend = "${{ matrix.name }}"
295+
lines = [
296+
f"## E2E results — {backend}",
297+
f"**✅ {totals['passed']} passed · ❌ {totals['failed']} failed · ⏭ {totals['skipped']} skipped**",
298+
"",
299+
"| Class | Test | Duration | Result |",
300+
"|-------|------|----------|--------|",
301+
]
302+
for cls, name, dur, status in rows:
303+
lines.append(f"| {cls} | {name} | {dur} | {status} |")
304+
305+
summary = os.environ.get("GITHUB_STEP_SUMMARY", "/dev/null")
306+
with open(summary, "a") as fh:
307+
fh.write("\n".join(lines) + "\n")
308+
- name: Upload E2E reports
309+
uses: actions/upload-artifact@v6
310+
if: always()
311+
with:
312+
name: e2e-reports-${{ matrix.name }}
313+
path: "e2e/build/reports"
314+
146315
build-ui:
147316
runs-on: ubuntu-latest
148-
container: cypress/browsers:node-22.11.0-chrome-130.0.6723.116-1-ff-132.0.1-edge-130.0.2849.68-1
149317
defaults:
150318
run:
151319
working-directory: ui
152320
steps:
153321
- uses: actions/checkout@v6
154322

323+
- name: Set up Node
324+
uses: actions/setup-node@v4
325+
with:
326+
node-version: "22"
327+
cache: "yarn"
328+
cache-dependency-path: ui/yarn.lock
329+
155330
- name: Install Dependencies
156331
run: yarn install
157332

158333
- name: Build UI
159334
run: yarn run build
160335

161-
- name: Run E2E Tests
162-
uses: cypress-io/github-action@v7
336+
- name: Cache Playwright browsers
337+
uses: actions/cache@v4
338+
id: playwright-cache
163339
with:
164-
working-directory: ui
165-
install: false
166-
start: yarn run serve-build
167-
wait-on: "http://localhost:5000"
340+
path: ~/.cache/ms-playwright
341+
key: playwright-chromium-${{ hashFiles('ui/yarn.lock') }}
168342

169-
- name: Run Component Tests
170-
uses: cypress-io/github-action@v7
171-
with:
172-
working-directory: ui
173-
install: false
174-
component: true
343+
- name: Install Playwright browsers
344+
if: steps.playwright-cache.outputs.cache-hit != 'true'
345+
run: npx playwright install --with-deps chromium
175346

176-
- name: Archive test screenshots
177-
uses: actions/upload-artifact@v6
178-
if: failure()
179-
with:
180-
name: cypress-screenshots
181-
path: ui/cypress/screenshots
347+
- name: Install Playwright browser deps (cached)
348+
if: steps.playwright-cache.outputs.cache-hit == 'true'
349+
run: npx playwright install-deps chromium
182350

183-
- name: Archive test videos
351+
- name: Run Playwright E2E Tests
352+
run: yarn test:e2e
353+
354+
- name: Upload Playwright report
184355
uses: actions/upload-artifact@v6
185-
if: always()
356+
if: failure()
186357
with:
187-
name: cypress-videos
188-
path: ui/cypress/videos
358+
name: playwright-report
359+
path: ui/playwright-report
360+
retention-days: 7

0 commit comments

Comments
 (0)