From 2da28e9a23dd48bf60415a31ffd5af37374b5c82 Mon Sep 17 00:00:00 2001 From: Oluwatobi Adelegan Date: Thu, 16 Apr 2026 18:41:58 +0100 Subject: [PATCH 1/2] QVAC-17318 infra: add Device Farm artifact downloads to all mobile integration test pipelines Add automatic downloading and uploading of Device Farm artifacts (logs, test specs, results) as GitHub Actions artifacts across all mobile integration test workflows. Excludes video artifacts on Android to reduce artifact size, keeping video only for iOS where C++ logs are unavailable. New artifact downloads: decoder-audio, llamacpp-embed, diffusion, ocr-onnx. Android video exclusion: all 9 workflows including llm, nmt, tts, whisper, parakeet. Made-with: Cursor --- ...ration-mobile-test-lib-infer-diffusion.yml | 139 ++++++++++++++++++ .../integration-mobile-test-ocr-onnx.yml | 139 ++++++++++++++++++ ...ion-mobile-test-qvac-lib-decoder-audio.yml | 139 ++++++++++++++++++ ...ile-test-qvac-lib-infer-llamacpp-embed.yml | 139 ++++++++++++++++++ ...obile-test-qvac-lib-infer-llamacpp-llm.yml | 13 ++ ...tion-mobile-test-qvac-lib-infer-nmtcpp.yml | 18 +++ ...on-mobile-test-qvac-lib-infer-onnx-tts.yml | 19 +++ ...on-mobile-test-qvac-lib-infer-parakeet.yml | 19 +++ ...-mobile-test-qvac-lib-infer-whispercpp.yml | 19 +++ 9 files changed, 644 insertions(+) diff --git a/.github/workflows/integration-mobile-test-lib-infer-diffusion.yml b/.github/workflows/integration-mobile-test-lib-infer-diffusion.yml index 737f63b690..7063d2223a 100644 --- a/.github/workflows/integration-mobile-test-lib-infer-diffusion.yml +++ b/.github/workflows/integration-mobile-test-lib-infer-diffusion.yml @@ -1293,3 +1293,142 @@ jobs: echo "✅ All Device Farm tests passed!" echo " Your tests: $USER_PASSED passed (out of $USER_TEST_COUNT total)" echo " Device Farm total: $TOTAL | Passed: $PASSED | Failed: $FAILED | Skipped: $SKIPPED" + + - name: Refresh AWS credentials for log download + if: always() && steps.schedule_run.outputs.run_arn + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-west-2 + role-session-name: device-farm-logs + + - name: Download Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + run: | + RUN_ARN="${{ steps.schedule_run.outputs.run_arn }}" + LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" + mkdir -p "$LOG_DIR" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📥 DOWNLOADING DEVICE FARM LOGS" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Logs are downloaded so anyone with repo access can view them" + echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" + + RUN_DETAILS=$(aws devicefarm get-run --arn "$RUN_ARN" --output json 2>/dev/null || echo '{}') + RUN_LABEL=$(echo "$RUN_DETAILS" | jq -r '.run.name // "unknown"') + echo "" + echo "========================================" + echo "📦 Run: $RUN_LABEL" + echo "========================================" + + SAFE_RUN=$(echo "$RUN_LABEL" | tr ' /' '__' | tr -cd '[:alnum:]_-') + JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --output json 2>/dev/null || echo '{"jobs":[]}') + + for JOB_ARN in $(echo "$JOBS" | jq -r '.jobs[].arn'); do + DEVICE_NAME=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .device.name // "unknown"') + JOB_RESULT=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .result // "UNKNOWN"') + SAFE_NAME=$(echo "$DEVICE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📱 $DEVICE_NAME ($JOB_RESULT)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + SUITES=$(aws devicefarm list-suites --arn "$JOB_ARN" --output json 2>/dev/null || echo '{"suites":[]}') + + for SUITE_ARN in $(echo "$SUITES" | jq -r '.suites[].arn'); do + SUITE_NAME=$(echo "$SUITES" | jq -r --arg arn "$SUITE_ARN" '.suites[] | select(.arn == $arn) | .name // "unknown"') + SAFE_SUITE=$(echo "$SUITE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME" + + if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then + echo "" + echo "::group::📋 [$DEVICE_NAME] $SUITE_NAME — $ART_NAME" + cat "$DEST" 2>/dev/null || true + echo "::endgroup::" + fi + fi + done + + LOG_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type LOG --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$LOG_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)" + fi + done + done + + JOB_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$JOB_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + echo "$JOB_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded (job-level): $ART_NAME" + fi + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 All downloaded logs:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)" + + - name: Upload Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + uses: actions/upload-artifact@v4 + with: + name: devicefarm-logs-diffusion-${{ matrix.platform }} + path: devicefarm-logs/ + retention-days: 30 + if-no-files-found: ignore diff --git a/.github/workflows/integration-mobile-test-ocr-onnx.yml b/.github/workflows/integration-mobile-test-ocr-onnx.yml index 6fadc5d264..54f9cd7653 100644 --- a/.github/workflows/integration-mobile-test-ocr-onnx.yml +++ b/.github/workflows/integration-mobile-test-ocr-onnx.yml @@ -1355,6 +1355,145 @@ jobs: echo " Your tests: $USER_PASSED passed (out of $USER_TEST_COUNT total)" echo " Device Farm total: $TOTAL | Passed: $PASSED | Failed: $FAILED | Skipped: $SKIPPED" + - name: Refresh AWS credentials for log download + if: always() && steps.schedule_run.outputs.run_arn + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-west-2 + role-session-name: device-farm-logs + + - name: Download Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + run: | + RUN_ARN="${{ steps.schedule_run.outputs.run_arn }}" + LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" + mkdir -p "$LOG_DIR" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📥 DOWNLOADING DEVICE FARM LOGS" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Logs are downloaded so anyone with repo access can view them" + echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" + + RUN_DETAILS=$(aws devicefarm get-run --arn "$RUN_ARN" --output json 2>/dev/null || echo '{}') + RUN_LABEL=$(echo "$RUN_DETAILS" | jq -r '.run.name // "unknown"') + echo "" + echo "========================================" + echo "📦 Run: $RUN_LABEL" + echo "========================================" + + SAFE_RUN=$(echo "$RUN_LABEL" | tr ' /' '__' | tr -cd '[:alnum:]_-') + JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --output json 2>/dev/null || echo '{"jobs":[]}') + + for JOB_ARN in $(echo "$JOBS" | jq -r '.jobs[].arn'); do + DEVICE_NAME=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .device.name // "unknown"') + JOB_RESULT=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .result // "UNKNOWN"') + SAFE_NAME=$(echo "$DEVICE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📱 $DEVICE_NAME ($JOB_RESULT)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + SUITES=$(aws devicefarm list-suites --arn "$JOB_ARN" --output json 2>/dev/null || echo '{"suites":[]}') + + for SUITE_ARN in $(echo "$SUITES" | jq -r '.suites[].arn'); do + SUITE_NAME=$(echo "$SUITES" | jq -r --arg arn "$SUITE_ARN" '.suites[] | select(.arn == $arn) | .name // "unknown"') + SAFE_SUITE=$(echo "$SUITE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME" + + if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then + echo "" + echo "::group::📋 [$DEVICE_NAME] $SUITE_NAME — $ART_NAME" + cat "$DEST" 2>/dev/null || true + echo "::endgroup::" + fi + fi + done + + LOG_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type LOG --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$LOG_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)" + fi + done + done + + JOB_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$JOB_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + echo "$JOB_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded (job-level): $ART_NAME" + fi + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 All downloaded logs:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)" + + - name: Upload Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + uses: actions/upload-artifact@v4 + with: + name: devicefarm-logs-ocr-onnx-${{ matrix.platform }} + path: devicefarm-logs/ + retention-days: 30 + if-no-files-found: ignore + - name: Comment PR with results if: always() && github.event.pull_request.number uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # 8.0.0 diff --git a/.github/workflows/integration-mobile-test-qvac-lib-decoder-audio.yml b/.github/workflows/integration-mobile-test-qvac-lib-decoder-audio.yml index 2782aeb639..edfe28c0da 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-decoder-audio.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-decoder-audio.yml @@ -1222,3 +1222,142 @@ jobs: echo " Your tests: $USER_PASSED passed (out of $USER_TEST_COUNT total)" echo " Device Farm total: $TOTAL | Passed: $PASSED | Failed: $FAILED | Skipped: $SKIPPED" + - name: Refresh AWS credentials for log download + if: always() && steps.schedule_run.outputs.run_arn + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-west-2 + role-session-name: device-farm-logs + + - name: Download Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + run: | + RUN_ARN="${{ steps.schedule_run.outputs.run_arn }}" + LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" + mkdir -p "$LOG_DIR" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📥 DOWNLOADING DEVICE FARM LOGS" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Logs are downloaded so anyone with repo access can view them" + echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" + + RUN_DETAILS=$(aws devicefarm get-run --arn "$RUN_ARN" --output json 2>/dev/null || echo '{}') + RUN_LABEL=$(echo "$RUN_DETAILS" | jq -r '.run.name // "unknown"') + echo "" + echo "========================================" + echo "📦 Run: $RUN_LABEL" + echo "========================================" + + SAFE_RUN=$(echo "$RUN_LABEL" | tr ' /' '__' | tr -cd '[:alnum:]_-') + JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --output json 2>/dev/null || echo '{"jobs":[]}') + + for JOB_ARN in $(echo "$JOBS" | jq -r '.jobs[].arn'); do + DEVICE_NAME=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .device.name // "unknown"') + JOB_RESULT=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .result // "UNKNOWN"') + SAFE_NAME=$(echo "$DEVICE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📱 $DEVICE_NAME ($JOB_RESULT)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + SUITES=$(aws devicefarm list-suites --arn "$JOB_ARN" --output json 2>/dev/null || echo '{"suites":[]}') + + for SUITE_ARN in $(echo "$SUITES" | jq -r '.suites[].arn'); do + SUITE_NAME=$(echo "$SUITES" | jq -r --arg arn "$SUITE_ARN" '.suites[] | select(.arn == $arn) | .name // "unknown"') + SAFE_SUITE=$(echo "$SUITE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME" + + if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then + echo "" + echo "::group::📋 [$DEVICE_NAME] $SUITE_NAME — $ART_NAME" + cat "$DEST" 2>/dev/null || true + echo "::endgroup::" + fi + fi + done + + LOG_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type LOG --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$LOG_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)" + fi + done + done + + JOB_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$JOB_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + echo "$JOB_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded (job-level): $ART_NAME" + fi + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 All downloaded logs:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)" + + - name: Upload Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + uses: actions/upload-artifact@v4 + with: + name: devicefarm-logs-decoder-audio-${{ matrix.platform }} + path: devicefarm-logs/ + retention-days: 30 + if-no-files-found: ignore + diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-embed.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-embed.yml index 4ba1801f97..7b633bd4b9 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-embed.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-embed.yml @@ -1267,3 +1267,142 @@ jobs: echo "✅ All Device Farm tests passed!" echo " Your tests: $USER_PASSED passed (out of $USER_TEST_COUNT total)" echo " Device Farm total: $TOTAL | Passed: $PASSED | Failed: $FAILED | Skipped: $SKIPPED" + + - name: Refresh AWS credentials for log download + if: always() && steps.schedule_run.outputs.run_arn + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-west-2 + role-session-name: device-farm-logs + + - name: Download Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + run: | + RUN_ARN="${{ steps.schedule_run.outputs.run_arn }}" + LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" + mkdir -p "$LOG_DIR" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📥 DOWNLOADING DEVICE FARM LOGS" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Logs are downloaded so anyone with repo access can view them" + echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" + + RUN_DETAILS=$(aws devicefarm get-run --arn "$RUN_ARN" --output json 2>/dev/null || echo '{}') + RUN_LABEL=$(echo "$RUN_DETAILS" | jq -r '.run.name // "unknown"') + echo "" + echo "========================================" + echo "📦 Run: $RUN_LABEL" + echo "========================================" + + SAFE_RUN=$(echo "$RUN_LABEL" | tr ' /' '__' | tr -cd '[:alnum:]_-') + JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --output json 2>/dev/null || echo '{"jobs":[]}') + + for JOB_ARN in $(echo "$JOBS" | jq -r '.jobs[].arn'); do + DEVICE_NAME=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .device.name // "unknown"') + JOB_RESULT=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .result // "UNKNOWN"') + SAFE_NAME=$(echo "$DEVICE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📱 $DEVICE_NAME ($JOB_RESULT)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + SUITES=$(aws devicefarm list-suites --arn "$JOB_ARN" --output json 2>/dev/null || echo '{"suites":[]}') + + for SUITE_ARN in $(echo "$SUITES" | jq -r '.suites[].arn'); do + SUITE_NAME=$(echo "$SUITES" | jq -r --arg arn "$SUITE_ARN" '.suites[] | select(.arn == $arn) | .name // "unknown"') + SAFE_SUITE=$(echo "$SUITE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME" + + if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then + echo "" + echo "::group::📋 [$DEVICE_NAME] $SUITE_NAME — $ART_NAME" + cat "$DEST" 2>/dev/null || true + echo "::endgroup::" + fi + fi + done + + LOG_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type LOG --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$LOG_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)" + fi + done + done + + JOB_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$JOB_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + echo "$JOB_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded (job-level): $ART_NAME" + fi + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 All downloaded logs:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)" + + - name: Upload Device Farm Logs + if: always() && steps.schedule_run.outputs.run_arn + uses: actions/upload-artifact@v4 + with: + name: devicefarm-logs-llamacpp-embed-${{ matrix.platform }} + path: devicefarm-logs/ + retention-days: 30 + if-no-files-found: ignore diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-llm.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-llm.yml index 08ebbd7ef3..3086ba78bb 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-llm.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-llamacpp-llm.yml @@ -1471,6 +1471,7 @@ jobs: RUN_ARN_8="${{ steps.schedule_run.outputs.run_arn_8 }}" RUN_COUNT="${{ steps.schedule_run.outputs.run_count }}" LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" mkdir -p "$LOG_DIR" RUN_ARNS=("$RUN_ARN_1") @@ -1518,6 +1519,12 @@ jobs: ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then @@ -1549,6 +1556,12 @@ jobs: ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-nmtcpp.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-nmtcpp.yml index ea2aa0dddd..fd6e9790f6 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-nmtcpp.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-nmtcpp.yml @@ -1497,6 +1497,7 @@ jobs: RUN_ARN_2="${{ steps.schedule_run.outputs.run_arn_2 }}" RUN_COUNT="${{ steps.schedule_run.outputs.run_count }}" LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" mkdir -p "$LOG_DIR" echo "" @@ -1506,6 +1507,9 @@ jobs: echo "" echo "Logs are downloaded so anyone with repo access can view them" echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi echo "" RUN_ARNS=("$RUN_ARN_1") @@ -1547,6 +1551,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" @@ -1586,6 +1597,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-onnx-tts.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-onnx-tts.yml index e72dcb9504..755102162d 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-onnx-tts.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-onnx-tts.yml @@ -1423,6 +1423,7 @@ jobs: RUN_ARN_2="${{ steps.schedule_run.outputs.run_arn_2 }}" RUN_COUNT="${{ steps.schedule_run.outputs.run_count }}" LOG_DIR="devicefarm-logs/${{ matrix.platform }}-${{ matrix.variant }}" + PLATFORM="${{ matrix.platform }}" mkdir -p "$LOG_DIR" echo "" @@ -1430,6 +1431,10 @@ jobs: echo "📥 DOWNLOADING DEVICE FARM LOGS" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" RUN_ARNS=("$RUN_ARN_1") if [ "$RUN_COUNT" -ge 2 ] && [ -n "$RUN_ARN_2" ]; then @@ -1471,6 +1476,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" @@ -1510,6 +1522,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-parakeet.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-parakeet.yml index e3836aef39..402518efdf 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-parakeet.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-parakeet.yml @@ -1346,6 +1346,7 @@ jobs: RUN_ARN_2="${{ steps.schedule_run.outputs.run_arn_2 }}" RUN_COUNT="${{ steps.schedule_run.outputs.run_count }}" LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" mkdir -p "$LOG_DIR" echo "" @@ -1353,6 +1354,10 @@ jobs: echo "📥 DOWNLOADING DEVICE FARM LOGS" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" RUN_ARNS=("$RUN_ARN_1") if [ "$RUN_COUNT" -ge 2 ] && [ -n "$RUN_ARN_2" ]; then @@ -1394,6 +1399,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" @@ -1433,6 +1445,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" diff --git a/.github/workflows/integration-mobile-test-qvac-lib-infer-whispercpp.yml b/.github/workflows/integration-mobile-test-qvac-lib-infer-whispercpp.yml index aef17fa639..3565b665e8 100644 --- a/.github/workflows/integration-mobile-test-qvac-lib-infer-whispercpp.yml +++ b/.github/workflows/integration-mobile-test-qvac-lib-infer-whispercpp.yml @@ -1381,6 +1381,7 @@ jobs: RUN_ARN_2="${{ steps.schedule_run.outputs.run_arn_2 }}" RUN_COUNT="${{ steps.schedule_run.outputs.run_count }}" LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" mkdir -p "$LOG_DIR" echo "" @@ -1388,6 +1389,10 @@ jobs: echo "📥 DOWNLOADING DEVICE FARM LOGS" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" RUN_ARNS=("$RUN_ARN_1") if [ "$RUN_COUNT" -ge 2 ] && [ -n "$RUN_ARN_2" ]; then @@ -1429,6 +1434,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" @@ -1468,6 +1480,13 @@ jobs: ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') [ -z "$ART_URL" ] && continue + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" From b2c16f77b39f191429e73e249afe5b400a323a39 Mon Sep 17 00:00:00 2001 From: Oluwatobi Adelegan Date: Fri, 17 Apr 2026 10:57:50 +0100 Subject: [PATCH 2/2] QVAC-17318 infra: add generic log download alongside perf download for OCR Keep main's perf-specific artifact download (for perf report extraction) and add the generic Device Farm log download for both perf + regular runs. Includes Android video exclusion. Both artifact sets uploaded separately (df-raw-logs for perf, devicefarm-logs for full logs). Made-with: Cursor --- .../integration-mobile-test-ocr-onnx.yml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/.github/workflows/integration-mobile-test-ocr-onnx.yml b/.github/workflows/integration-mobile-test-ocr-onnx.yml index c2326a8321..742437fef8 100644 --- a/.github/workflows/integration-mobile-test-ocr-onnx.yml +++ b/.github/workflows/integration-mobile-test-ocr-onnx.yml @@ -1641,6 +1641,156 @@ jobs: retention-days: 90 if-no-files-found: ignore + - name: Refresh AWS credentials for log download + if: always() && (steps.schedule_run.outputs.run_arn_perf || steps.schedule_run.outputs.run_arn_regular) + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-west-2 + role-session-name: device-farm-logs + + - name: Download Device Farm Logs (all runs) + if: always() && (steps.schedule_run.outputs.run_arn_perf || steps.schedule_run.outputs.run_arn_regular) + run: | + RUN_ARN_PERF="${{ steps.schedule_run.outputs.run_arn_perf }}" + RUN_ARN_REGULAR="${{ steps.schedule_run.outputs.run_arn_regular }}" + LOG_DIR="devicefarm-logs/${{ matrix.platform }}" + PLATFORM="${{ matrix.platform }}" + mkdir -p "$LOG_DIR" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📥 DOWNLOADING DEVICE FARM LOGS (ALL RUNS)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Logs are downloaded so anyone with repo access can view them" + echo "without needing AWS Device Farm credentials." + if [ "$PLATFORM" = "Android" ]; then + echo "ℹ️ Skipping video artifacts on Android to reduce artifact size." + fi + echo "" + + RUN_ARNS=() + if [ -n "$RUN_ARN_PERF" ]; then + RUN_ARNS+=("$RUN_ARN_PERF") + fi + if [ -n "$RUN_ARN_REGULAR" ]; then + RUN_ARNS+=("$RUN_ARN_REGULAR") + fi + + for RUN_ARN in "${RUN_ARNS[@]}"; do + RUN_DETAILS=$(aws devicefarm get-run --arn "$RUN_ARN" --output json 2>/dev/null || echo '{}') + RUN_LABEL=$(echo "$RUN_DETAILS" | jq -r '.run.name // "unknown"') + echo "" + echo "========================================" + echo "📦 Run: $RUN_LABEL" + echo "========================================" + + SAFE_RUN=$(echo "$RUN_LABEL" | tr ' /' '__' | tr -cd '[:alnum:]_-') + JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --output json 2>/dev/null || echo '{"jobs":[]}') + + for JOB_ARN in $(echo "$JOBS" | jq -r '.jobs[].arn'); do + DEVICE_NAME=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .device.name // "unknown"') + JOB_RESULT=$(echo "$JOBS" | jq -r --arg arn "$JOB_ARN" '.jobs[] | select(.arn == $arn) | .result // "UNKNOWN"') + SAFE_NAME=$(echo "$DEVICE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📱 $DEVICE_NAME ($JOB_RESULT)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + SUITES=$(aws devicefarm list-suites --arn "$JOB_ARN" --output json 2>/dev/null || echo '{"suites":[]}') + + for SUITE_ARN in $(echo "$SUITES" | jq -r '.suites[].arn'); do + SUITE_NAME=$(echo "$SUITES" | jq -r --arg arn "$SUITE_ARN" '.suites[] | select(.arn == $arn) | .name // "unknown"') + SAFE_SUITE=$(echo "$SUITE_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + + ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): $SUITE_NAME / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME" + + if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then + echo "" + echo "::group::📋 [$DEVICE_NAME] $SUITE_NAME — $ART_NAME" + cat "$DEST" 2>/dev/null || true + echo "::endgroup::" + fi + fi + done + + LOG_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$SUITE_ARN" --type LOG --output json 2>/dev/null || echo '{"artifacts":[]}') + + echo "$LOG_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)" + fi + done + done + + JOB_ARTIFACTS=$(aws devicefarm list-artifacts --arn "$JOB_ARN" --type FILE --output json 2>/dev/null || echo '{"artifacts":[]}') + echo "$JOB_ARTIFACTS" | jq -c '.artifacts[]' 2>/dev/null | while read -r ARTIFACT; do + ART_NAME=$(echo "$ARTIFACT" | jq -r '.name // "unknown"') + ART_URL=$(echo "$ARTIFACT" | jq -r '.url // empty') + ART_EXT=$(echo "$ARTIFACT" | jq -r '.extension // "txt"') + [ -z "$ART_URL" ] && continue + + if [ "$PLATFORM" = "Android" ]; then + if echo "$ART_NAME" | grep -qiE "^video$" || echo "$ART_EXT" | grep -qiE "^mp4$"; then + echo " Skipped (video): job-level / $ART_NAME" + continue + fi + fi + + SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-') + DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}" + + if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then + echo " Downloaded (job-level): $ART_NAME" + fi + done + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "📦 All downloaded logs:" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)" + + - name: Upload Device Farm Logs + if: always() && (steps.schedule_run.outputs.run_arn_perf || steps.schedule_run.outputs.run_arn_regular) + uses: actions/upload-artifact@v4 + with: + name: devicefarm-logs-ocr-onnx-${{ matrix.platform }} + path: devicefarm-logs/ + retention-days: 30 + if-no-files-found: ignore + combine-reports: name: Combined Performance Report needs: [build-and-test]