@@ -269,7 +269,7 @@ jobs:
269269 run : |
270270 set -eu
271271
272- docker buildx bake frontend
272+ docker buildx bake frontend --set frontend.args.DALEC_FRONTEND_COVERAGE=1
273273 if [ "${TEST_SUITE}" = "other" ]; then
274274 exit 0
275275 fi
@@ -280,22 +280,53 @@ jobs:
280280 worker="windowscross"
281281 fi
282282 export WORKER_TARGET=${worker}/worker
283- docker buildx bake worker
283+ docker buildx bake worker --set frontend.args.DALEC_FRONTEND_COVERAGE=1
284284 env :
285285 TEST_SUITE : ${{ matrix.suite }}
286- - name : Run integration tests
286+ - name : Run integration tests (with coverage tracking)
287287 run : |
288288 set -ex
289- if [ -n "${TEST_SUITE}" ] && [ ! "${TEST_SUITE}" = "other" ]; then
289+ mkdir -p coverage
290+ export DALEC_FRONTEND_GOCOVERDIR="${GITHUB_WORKSPACE}/coverage/frontend-${TEST_SUITE}"
291+
292+ run=""
293+ skip=""
294+ if [ -n "${TEST_SUITE}" ] && [ "${TEST_SUITE}" != "other" ]; then
290295 run="-run=${TEST_SUITE}"
291296 fi
292297 if [ -n "${TEST_SKIP}" ]; then
293298 skip="-skip=${TEST_SKIP}"
294299 fi
295- go test -timeout=59m -v -json ${run} ${skip} ./test | go run ./cmd/test2json2gha --slow 120s --logdir /tmp/testlogs
300+
301+ go test -timeout=59m -v -json \
302+ -covermode=set -coverpkg=./... \
303+ -coverprofile="coverage/integration-${TEST_SUITE}.out" \
304+ ${run} ${skip} ./test \
305+ | go run ./cmd/test2json2gha --slow 120s --logdir /tmp/testlogs
306+
307+ # Convert frontend covdata -> legacy coverprofile (mode: set)
308+ if ! ls "${DALEC_FRONTEND_GOCOVERDIR}"/covmeta.* >/dev/null 2>&1; then
309+ echo "::error::No frontend coverage covmeta.* found in ${DALEC_FRONTEND_GOCOVERDIR} (frontend coverage not collected)"
310+ exit 1
311+ fi
312+ go tool covdata textfmt \
313+ -i="${DALEC_FRONTEND_GOCOVERDIR}" \
314+ -o="coverage/frontend-${TEST_SUITE}.out"
296315 env :
297316 TEST_SUITE : ${{ matrix.suite }}
298317 TEST_SKIP : ${{ matrix.skip }}
318+
319+ - name : Upload integration coverage profile
320+ if : always()
321+ uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
322+ with :
323+ name : coverage-integration-${{ matrix.suite }}
324+ path : |
325+ coverage/integration-${{ matrix.suite }}.out
326+ coverage/frontend-${{ matrix.suite }}.out
327+ if-no-files-found : ignore
328+ retention-days : 7
329+
299330 - name : Get traces
300331 if : always()
301332 run : |
@@ -354,8 +385,27 @@ jobs:
354385 cache : false
355386 - name : download deps
356387 run : go mod download
357- - name : Run unit tests
358- run : go test -v --test.short --json ./... | go run ./cmd/test2json2gha
388+ - name : Run unit tests (with coverage tracking)
389+ run : |
390+ set -eux
391+ mkdir -p coverage
392+
393+ pkgs="$(go list ./... | grep -v '/test$' | grep -v '/test/' )"
394+ go test -v --test.short --json \
395+ -covermode=set \
396+ -coverprofile="coverage/unit.out" \
397+ ${pkgs} \
398+ | go run ./cmd/test2json2gha
399+ - name : Upload unit coverage profile
400+ if : always()
401+ uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
402+ with :
403+ name : coverage-unit
404+ path : coverage/unit.out
405+ if-no-files-found : ignore
406+ retention-days : 7
407+
408+
359409
360410 e2e :
361411 runs-on : ubuntu-22.04
@@ -443,3 +493,82 @@ jobs:
443493 path : ${{ steps.dump-logs.outputs.DOCKERD_LOG_PATH }}
444494 retention-days : 1
445495
496+ coverage-report :
497+ runs-on : ubuntu-22.04
498+ needs :
499+ - unit
500+ - integration
501+
502+ steps :
503+ - name : Harden Runner
504+ uses : step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
505+ with :
506+ egress-policy : audit
507+
508+ - name : Checkout
509+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
510+
511+ - name : Setup Go
512+ uses : actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
513+ with :
514+ go-version : " 1.25"
515+ cache : false
516+
517+ - name : Download deps
518+ run : go mod download
519+
520+ - name : Download unit coverage artifact
521+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
522+ with :
523+ name : coverage-unit
524+ path : coverage
525+
526+ - name : Download integration coverage artifacts
527+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
528+ with :
529+ path : coverage/_integration
530+
531+ - name : Merge coverage + generate report
532+ run : |
533+ set -eux
534+ go install github.com/wadey/gocovmerge@latest
535+
536+ integration_profiles="$(find coverage/_integration -type f -name 'integration-*.out' | sort | tr '\n' ' ')"
537+ frontend_profiles="$(find coverage/_integration -type f -name 'frontend-*.out' | sort | tr '\n' ' ')"
538+ if [ -z "${integration_profiles}" ]; then
539+ echo "::error::No integration coverage profiles found"
540+ exit 1
541+ fi
542+
543+ if [ -z "${frontend_profiles}" ]; then
544+ echo "::error::No frontend coverage profiles found"
545+ exit 1
546+ fi
547+
548+ if [ ! -f coverage/unit.out ]; then
549+ echo "::error::Unit coverage profile not found (coverage/unit.out)"
550+ exit 1
551+ fi
552+
553+ "$(go env GOPATH)/bin/gocovmerge" coverage/unit.out ${integration_profiles} ${frontend_profiles} > coverage/all.out
554+
555+ go tool cover -func=coverage/all.out | tee coverage/summary.txt
556+ go tool cover -html=coverage/all.out -o coverage/index.html
557+
558+ total="$(tail -n 1 coverage/summary.txt | awk '{print $3}')"
559+ {
560+ echo "## Coverage"
561+ echo
562+ echo "- Total: **${total}**"
563+ echo "- Profiles merged: $(echo "${integration_profiles}" | wc -w) integration + $(echo "${frontend_profiles}" | wc -w) frontend"
564+ } >> "${GITHUB_STEP_SUMMARY}"
565+
566+ - name : Upload merged coverage report
567+ uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
568+ with :
569+ name : coverage-report
570+ path : |
571+ coverage/all.out
572+ coverage/summary.txt
573+ coverage/index.html
574+ retention-days : 14
0 commit comments