From 9bed1aa783b2906b48422844e210a58fecd1f186 Mon Sep 17 00:00:00 2001 From: Vincent Ahrend Date: Fri, 31 Oct 2025 11:37:56 +0100 Subject: [PATCH 1/4] Remove empty inputs section --- .github/workflows/swift-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/swift-ci.yml b/.github/workflows/swift-ci.yml index e1a2fba5d..640156061 100644 --- a/.github/workflows/swift-ci.yml +++ b/.github/workflows/swift-ci.yml @@ -379,7 +379,6 @@ jobs: - name: Get BrowserStack build info id: build-info uses: ./.github/actions/generate-browserstack-names - with: - name: Seed and execute XCUITests on BrowserStack id: test From ae0853ef40e82574162cc285a7cf706aa57f9e77 Mon Sep 17 00:00:00 2001 From: Vincent Ahrend Date: Fri, 31 Oct 2025 11:40:43 +0100 Subject: [PATCH 2/4] Remove empty inputs from other workflows --- .github/workflows/android-cpp-ci.yml | 1 - .github/workflows/android-java-ci.yml | 547 ++++++++++++------------ .github/workflows/android-kotlin-ci.yml | 1 - .github/workflows/java-spring-ci.yml | 463 ++++++++++---------- 4 files changed, 503 insertions(+), 509 deletions(-) diff --git a/.github/workflows/android-cpp-ci.yml b/.github/workflows/android-cpp-ci.yml index 39fc2ddd8..baf807876 100644 --- a/.github/workflows/android-cpp-ci.yml +++ b/.github/workflows/android-cpp-ci.yml @@ -165,7 +165,6 @@ jobs: - name: Get BrowserStack build info id: build-info uses: ./.github/actions/generate-browserstack-names - with: - name: Seed and execute Appium tests on BrowserStack id: test diff --git a/.github/workflows/android-java-ci.yml b/.github/workflows/android-java-ci.yml index ada466c02..0cdb6d05e 100644 --- a/.github/workflows/android-java-ci.yml +++ b/.github/workflows/android-java-ci.yml @@ -15,35 +15,35 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '17' - - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - android-java/.gradle - key: gradle-${{ runner.os }}-${{ hashFiles('android-java/gradle/wrapper/gradle-wrapper.properties', 'android-java/**/*.gradle*') }} - restore-keys: | - gradle-${{ runner.os }}- - - - name: Create test .env file - run: | - echo "DITTO_APP_ID=test" > .env - echo "DITTO_PLAYGROUND_TOKEN=test" >> .env - echo "DITTO_AUTH_URL=test" >> .env - echo "DITTO_WEBSOCKET_URL=test" >> .env - - - name: Run Android linting - working-directory: android-java - run: ./gradlew lint + - uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + android-java/.gradle + key: gradle-${{ runner.os }}-${{ hashFiles('android-java/gradle/wrapper/gradle-wrapper.properties', 'android-java/**/*.gradle*') }} + restore-keys: | + gradle-${{ runner.os }}- + + - name: Create test .env file + run: | + echo "DITTO_APP_ID=test" > .env + echo "DITTO_PLAYGROUND_TOKEN=test" >> .env + echo "DITTO_AUTH_URL=test" >> .env + echo "DITTO_WEBSOCKET_URL=test" >> .env + + - name: Run Android linting + working-directory: android-java + run: ./gradlew lint build: name: Build APKs @@ -52,49 +52,49 @@ jobs: timeout-minutes: 20 steps: - - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '17' - - - name: Setup Android SDK - uses: android-actions/setup-android@v3 - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 - - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - - name: Create .env file - run: | - echo "DITTO_APP_ID=${{ secrets.DITTO_APP_ID }}" > .env - echo "DITTO_PLAYGROUND_TOKEN=${{ secrets.DITTO_PLAYGROUND_TOKEN }}" >> .env - echo "DITTO_AUTH_URL=${{ secrets.DITTO_AUTH_URL }}" >> .env - echo "DITTO_WEBSOCKET_URL=${{ secrets.DITTO_WEBSOCKET_URL }}" >> .env - - - name: Build APKs - working-directory: android-java - run: ./gradlew assembleDebug assembleDebugAndroidTest - - - name: Upload APK artifacts - uses: actions/upload-artifact@v4 - with: - name: android-apks-${{ github.run_number }} - path: | - android-java/app/build/outputs/apk/debug/app-debug.apk - android-java/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk - retention-days: 1 + - uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Create .env file + run: | + echo "DITTO_APP_ID=${{ secrets.DITTO_APP_ID }}" > .env + echo "DITTO_PLAYGROUND_TOKEN=${{ secrets.DITTO_PLAYGROUND_TOKEN }}" >> .env + echo "DITTO_AUTH_URL=${{ secrets.DITTO_AUTH_URL }}" >> .env + echo "DITTO_WEBSOCKET_URL=${{ secrets.DITTO_WEBSOCKET_URL }}" >> .env + + - name: Build APKs + working-directory: android-java + run: ./gradlew assembleDebug assembleDebugAndroidTest + + - name: Upload APK artifacts + uses: actions/upload-artifact@v4 + with: + name: android-apks-${{ github.run_number }} + path: | + android-java/app/build/outputs/apk/debug/app-debug.apk + android-java/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk + retention-days: 1 browserstack-android: name: BrowserStack Device Testing @@ -106,197 +106,196 @@ jobs: build_id: ${{ steps.test.outputs.build_id }} steps: - - uses: actions/checkout@v4 - - - name: Download APK artifacts - uses: actions/download-artifact@v4 - with: - name: android-apks-${{ github.run_number }} - path: android-java/app/build/outputs/apk/ - - - name: Upload APKs to BrowserStack - id: upload - run: | - CREDS="${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" - - # Upload app APK - echo "Uploading app APK to BrowserStack..." - APP_RESPONSE=$(curl -u "$CREDS" \ - -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/app" \ - -F "file=@android-java/app/build/outputs/apk/debug/app-debug.apk" \ - -F "custom_id=ditto-android-java-app") - - APP_URL=$(echo "$APP_RESPONSE" | yq eval -p=json .app_url) - if [ "$APP_URL" = "null" ] || [ -z "$APP_URL" ]; then - echo "Error: Failed to upload app APK" - echo "Response: $APP_RESPONSE" - exit 1 - fi - echo "app_url=$APP_URL" >> "$GITHUB_OUTPUT" - echo "App APK uploaded: $APP_URL" - - # Upload test APK - echo "Uploading test APK to BrowserStack..." - TEST_RESPONSE=$(curl -u "$CREDS" \ - -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/test-suite" \ - -F "file=@android-java/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" \ - -F "custom_id=ditto-android-java-test") - - TEST_URL=$(echo "$TEST_RESPONSE" | yq eval -p=json .test_suite_url) - if [ "$TEST_URL" = "null" ] || [ -z "$TEST_URL" ]; then - echo "Error: Failed to upload test APK" - echo "Response: $TEST_RESPONSE" - exit 1 - fi - echo "test_url=$TEST_URL" >> "$GITHUB_OUTPUT" - echo "Test APK uploaded: $TEST_URL" - - - name: Get BrowserStack build info - id: build-info - uses: ./.github/actions/generate-browserstack-names - with: - - - name: Seed and execute tests on BrowserStack - id: test - uses: nick-fields/retry@v3 - with: - max_attempts: 5 - timeout_minutes: 20 - retry_wait_seconds: 900 - command: | - # Seed test task to Ditto Cloud - echo "Seeding test task to Ditto Cloud..." - TIMESTAMP=$(date +%s) - INVERTED_TIMESTAMP=$((9999999999 - TIMESTAMP)) - SEED_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \ - -H 'Content-type: application/json' \ - -H "Authorization: Bearer ${{ secrets.DITTO_API_KEY }}" \ - -d "{ - \"statement\": \"INSERT INTO tasks DOCUMENTS (:newTask) ON ID CONFLICT DO UPDATE\", - \"args\": { - \"newTask\": { - \"_id\": \"${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}\", - \"title\": \"${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}\", - \"done\": false, - \"deleted\": false - } - } - }" \ - "https://${{ secrets.DITTO_API_URL }}/api/v4/store/execute") - - HTTP_CODE=$(echo "$SEED_RESPONSE" | tail -n1) - BODY=$(echo "$SEED_RESPONSE" | sed '$d') - - if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 201 ]; then - TASK_TITLE="${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}" - echo "Seeded task: $TASK_TITLE" - else - echo "Error: Failed to seed task. HTTP Status: $HTTP_CODE" - echo "Response: $BODY" + - uses: actions/checkout@v4 + + - name: Download APK artifacts + uses: actions/download-artifact@v4 + with: + name: android-apks-${{ github.run_number }} + path: android-java/app/build/outputs/apk/ + + - name: Upload APKs to BrowserStack + id: upload + run: | + CREDS="${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" + + # Upload app APK + echo "Uploading app APK to BrowserStack..." + APP_RESPONSE=$(curl -u "$CREDS" \ + -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/app" \ + -F "file=@android-java/app/build/outputs/apk/debug/app-debug.apk" \ + -F "custom_id=ditto-android-java-app") + + APP_URL=$(echo "$APP_RESPONSE" | yq eval -p=json .app_url) + if [ "$APP_URL" = "null" ] || [ -z "$APP_URL" ]; then + echo "Error: Failed to upload app APK" + echo "Response: $APP_RESPONSE" exit 1 fi - - # Load devices from centralized config - DEVICES=$(yq eval -o=json -I=0 '.["android-java"].devices' .github/browserstack-devices.yml) - echo "Loaded devices: $DEVICES" - - # Create test execution request - BUILD_RESPONSE=$(curl -s -u '${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}' \ - -X POST 'https://api-cloud.browserstack.com/app-automate/espresso/v2/build' \ - -H 'Content-Type: application/json' \ - -d '{ - "app": "${{ steps.upload.outputs.app_url }}", - "testSuite": "${{ steps.upload.outputs.test_url }}", - "devices": '"$DEVICES"', - "project": "${{ steps.build-info.outputs.project-name }}", - "buildName": "${{ steps.build-info.outputs.build-name }}", - "buildTag": "${{ github.head_ref || github.ref_name }}", - "deviceLogs": true, - "video": true, - "networkLogs": true, - "autoGrantPermissions": true, - "instrumentationLogs": true, - "instrumentationOptions": { - "DITTO_CLOUD_TASK_TITLE": "'"$TASK_TITLE"'" - } - }') - - BUILD_ID=$(echo "$BUILD_RESPONSE" | yq eval .build_id) - - if [ "$BUILD_ID" = "null" ] || [ -z "$BUILD_ID" ]; then - echo "Error: Failed to create BrowserStack build" - echo "Response: $BUILD_RESPONSE" + echo "app_url=$APP_URL" >> "$GITHUB_OUTPUT" + echo "App APK uploaded: $APP_URL" + + # Upload test APK + echo "Uploading test APK to BrowserStack..." + TEST_RESPONSE=$(curl -u "$CREDS" \ + -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/test-suite" \ + -F "file=@android-java/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" \ + -F "custom_id=ditto-android-java-test") + + TEST_URL=$(echo "$TEST_RESPONSE" | yq eval -p=json .test_suite_url) + if [ "$TEST_URL" = "null" ] || [ -z "$TEST_URL" ]; then + echo "Error: Failed to upload test APK" + echo "Response: $TEST_RESPONSE" exit 1 fi + echo "test_url=$TEST_URL" >> "$GITHUB_OUTPUT" + echo "Test APK uploaded: $TEST_URL" + + - name: Get BrowserStack build info + id: build-info + uses: ./.github/actions/generate-browserstack-names + + - name: Seed and execute tests on BrowserStack + id: test + uses: nick-fields/retry@v3 + with: + max_attempts: 5 + timeout_minutes: 20 + retry_wait_seconds: 900 + command: | + # Seed test task to Ditto Cloud + echo "Seeding test task to Ditto Cloud..." + TIMESTAMP=$(date +%s) + INVERTED_TIMESTAMP=$((9999999999 - TIMESTAMP)) + SEED_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \ + -H 'Content-type: application/json' \ + -H "Authorization: Bearer ${{ secrets.DITTO_API_KEY }}" \ + -d "{ + \"statement\": \"INSERT INTO tasks DOCUMENTS (:newTask) ON ID CONFLICT DO UPDATE\", + \"args\": { + \"newTask\": { + \"_id\": \"${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}\", + \"title\": \"${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}\", + \"done\": false, + \"deleted\": false + } + } + }" \ + "https://${{ secrets.DITTO_API_URL }}/api/v4/store/execute") - echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT - echo "Build started with ID: $BUILD_ID" + HTTP_CODE=$(echo "$SEED_RESPONSE" | tail -n1) + BODY=$(echo "$SEED_RESPONSE" | sed '$d') - # Wait for test execution to complete - MAX_WAIT_TIME=1080 # 18 minutes - CHECK_INTERVAL=30 # Check every 30 seconds - ELAPSED=0 + if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 201 ]; then + TASK_TITLE="${INVERTED_TIMESTAMP}_android-java_ci_test_${{ github.run_id }}_${{ github.run_number }}" + echo "Seeded task: $TASK_TITLE" + else + echo "Error: Failed to seed task. HTTP Status: $HTTP_CODE" + echo "Response: $BODY" + exit 1 + fi - echo "⏳ Waiting for test execution to complete..." - while [ $ELAPSED -lt $MAX_WAIT_TIME ]; do - RESPONSE=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ - "https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID") + # Load devices from centralized config + DEVICES=$(yq eval -o=json -I=0 '.["android-java"].devices' .github/browserstack-devices.yml) + echo "Loaded devices: $DEVICES" + + # Create test execution request + BUILD_RESPONSE=$(curl -s -u '${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}' \ + -X POST 'https://api-cloud.browserstack.com/app-automate/espresso/v2/build' \ + -H 'Content-Type: application/json' \ + -d '{ + "app": "${{ steps.upload.outputs.app_url }}", + "testSuite": "${{ steps.upload.outputs.test_url }}", + "devices": '"$DEVICES"', + "project": "${{ steps.build-info.outputs.project-name }}", + "buildName": "${{ steps.build-info.outputs.build-name }}", + "buildTag": "${{ github.head_ref || github.ref_name }}", + "deviceLogs": true, + "video": true, + "networkLogs": true, + "autoGrantPermissions": true, + "instrumentationLogs": true, + "instrumentationOptions": { + "DITTO_CLOUD_TASK_TITLE": "'"$TASK_TITLE"'" + } + }') - STATUS=$(echo "$RESPONSE" | yq eval .status) + BUILD_ID=$(echo "$BUILD_RESPONSE" | yq eval .build_id) - if [ "$STATUS" = "null" ] || [ -z "$STATUS" ]; then - echo "⚠️ API error, retrying... (${ELAPSED}s elapsed)" - sleep $CHECK_INTERVAL - ELAPSED=$((ELAPSED + CHECK_INTERVAL)) - continue + if [ "$BUILD_ID" = "null" ] || [ -z "$BUILD_ID" ]; then + echo "Error: Failed to create BrowserStack build" + echo "Response: $BUILD_RESPONSE" + exit 1 fi - echo "📊 Status: $STATUS (${ELAPSED}s elapsed)" + echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT + echo "Build started with ID: $BUILD_ID" - # Check for completion - if [[ "$STATUS" =~ ^(done|failed|error|passed|completed)$ ]]; then - echo "✅ Build completed with status: $STATUS" - break - fi + # Wait for test execution to complete + MAX_WAIT_TIME=1080 # 18 minutes + CHECK_INTERVAL=30 # Check every 30 seconds + ELAPSED=0 - sleep $CHECK_INTERVAL - ELAPSED=$((ELAPSED + CHECK_INTERVAL)) - done + echo "⏳ Waiting for test execution to complete..." + while [ $ELAPSED -lt $MAX_WAIT_TIME ]; do + RESPONSE=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + "https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID") - # Get final results - FINAL_RESULT=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ - "https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID") + STATUS=$(echo "$RESPONSE" | yq eval .status) - echo "📋 Final results:" - echo "$FINAL_RESULT" | jq . + if [ "$STATUS" = "null" ] || [ -z "$STATUS" ]; then + echo "⚠️ API error, retrying... (${ELAPSED}s elapsed)" + sleep $CHECK_INTERVAL + ELAPSED=$((ELAPSED + CHECK_INTERVAL)) + continue + fi - # Validate and check results - if echo "$FINAL_RESULT" | jq -e .devices > /dev/null 2>&1; then - BUILD_STATUS=$(echo "$FINAL_RESULT" | yq eval .status) - if [ "$BUILD_STATUS" != "passed" ]; then - echo "❌ Tests failed with status: $BUILD_STATUS" + echo "📊 Status: $STATUS (${ELAPSED}s elapsed)" - FAILED_DEVICES=$(echo "$FINAL_RESULT" | yq eval '.devices[] | select(.sessions[].status != "passed") | .device') - if [ -n "$FAILED_DEVICES" ]; then - echo "Failed on devices: $FAILED_DEVICES" + # Check for completion + if [[ "$STATUS" =~ ^(done|failed|error|passed|completed)$ ]]; then + echo "✅ Build completed with status: $STATUS" + break + fi + + sleep $CHECK_INTERVAL + ELAPSED=$((ELAPSED + CHECK_INTERVAL)) + done + + # Get final results + FINAL_RESULT=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + "https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID") + + echo "📋 Final results:" + echo "$FINAL_RESULT" | jq . + + # Validate and check results + if echo "$FINAL_RESULT" | jq -e .devices > /dev/null 2>&1; then + BUILD_STATUS=$(echo "$FINAL_RESULT" | yq eval .status) + if [ "$BUILD_STATUS" != "passed" ]; then + echo "❌ Tests failed with status: $BUILD_STATUS" + + FAILED_DEVICES=$(echo "$FINAL_RESULT" | yq eval '.devices[] | select(.sessions[].status != "passed") | .device') + if [ -n "$FAILED_DEVICES" ]; then + echo "Failed on devices: $FAILED_DEVICES" + fi + exit 1 + else + echo "🎉 All tests passed successfully!" fi - exit 1 else - echo "🎉 All tests passed successfully!" + echo "⚠️ Could not parse final results" + exit 1 fi - else - echo "⚠️ Could not parse final results" - exit 1 - fi - - name: Upload test artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: | - android-java/app/build/outputs/apk/ - android-java/app/build/reports/ + - name: Upload test artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + android-java/app/build/outputs/apk/ + android-java/app/build/reports/ summary: name: CI Report @@ -305,37 +304,37 @@ jobs: if: always() steps: - - name: Report Results - run: | - echo "## 📱 Android Java CI" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # Overall status - if [[ "${{ needs.lint.result }}" == "success" && \ - "${{ needs.build.result }}" == "success" && \ - "${{ needs.browserstack-android.result }}" == "success" ]]; then - echo "**Overall Status:** ✅ All checks passed" >> $GITHUB_STEP_SUMMARY - else - echo "**Overall Status:** ❌ Failed" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY - echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Lint | ${{ needs.lint.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Build | ${{ needs.build.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "| BrowserStack Tests | ${{ needs.browserstack-android.result == 'success' && '✅ Passed' || (needs.browserstack-android.result == 'skipped' && '⏭️ Skipped') || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # BrowserStack link - if [[ "${{ needs.browserstack-android.result }}" != "skipped" ]]; then - echo "### BrowserStack Session" >> $GITHUB_STEP_SUMMARY + - name: Report Results + run: | + echo "## 📱 Android Java CI" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Overall status + if [[ "${{ needs.lint.result }}" == "success" && \ + "${{ needs.build.result }}" == "success" && \ + "${{ needs.browserstack-android.result }}" == "success" ]]; then + echo "**Overall Status:** ✅ All checks passed" >> $GITHUB_STEP_SUMMARY + else + echo "**Overall Status:** ❌ Failed" >> $GITHUB_STEP_SUMMARY + fi echo "" >> $GITHUB_STEP_SUMMARY - echo "🤖 [View Test Results](https://app-automate.browserstack.com/dashboard/v2/builds/${{ needs.browserstack-android.outputs.build_id }}/)" >> $GITHUB_STEP_SUMMARY + + echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY + echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Lint | ${{ needs.lint.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| Build | ${{ needs.build.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| BrowserStack Tests | ${{ needs.browserstack-android.result == 'success' && '✅ Passed' || (needs.browserstack-android.result == 'skipped' && '⏭️ Skipped') || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "**Tested Devices:**" >> $GITHUB_STEP_SUMMARY - echo "- Google Pixel 8 (Android 14)" >> $GITHUB_STEP_SUMMARY - echo "- Samsung Galaxy S23 (Android 13)" >> $GITHUB_STEP_SUMMARY - echo "- Google Pixel 6 (Android 12)" >> $GITHUB_STEP_SUMMARY - echo "- OnePlus 9 (Android 11)" >> $GITHUB_STEP_SUMMARY - fi + + # BrowserStack link + if [[ "${{ needs.browserstack-android.result }}" != "skipped" ]]; then + echo "### BrowserStack Session" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "🤖 [View Test Results](https://app-automate.browserstack.com/dashboard/v2/builds/${{ needs.browserstack-android.outputs.build_id }}/)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Tested Devices:**" >> $GITHUB_STEP_SUMMARY + echo "- Google Pixel 8 (Android 14)" >> $GITHUB_STEP_SUMMARY + echo "- Samsung Galaxy S23 (Android 13)" >> $GITHUB_STEP_SUMMARY + echo "- Google Pixel 6 (Android 12)" >> $GITHUB_STEP_SUMMARY + echo "- OnePlus 9 (Android 11)" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/android-kotlin-ci.yml b/.github/workflows/android-kotlin-ci.yml index 5c7234851..6cba4a704 100644 --- a/.github/workflows/android-kotlin-ci.yml +++ b/.github/workflows/android-kotlin-ci.yml @@ -172,7 +172,6 @@ jobs: - name: Get BrowserStack build info id: build-info uses: ./.github/actions/generate-browserstack-names - with: - name: Seed and execute tests on BrowserStack id: test diff --git a/.github/workflows/java-spring-ci.yml b/.github/workflows/java-spring-ci.yml index 57d55f959..418d77b11 100644 --- a/.github/workflows/java-spring-ci.yml +++ b/.github/workflows/java-spring-ci.yml @@ -13,7 +13,6 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - jobs: lint: name: Lint (ubuntu-latest) @@ -26,8 +25,8 @@ jobs: - name: Setup Java uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '17' + distribution: "temurin" + java-version: "17" - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 @@ -55,8 +54,8 @@ jobs: - name: Setup Java uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '17' + distribution: "temurin" + java-version: "17" - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 @@ -78,7 +77,6 @@ jobs: DITTO_ENABLE_CLOUD_SYNC: true run: ./gradlew bootJar -x test - - name: Upload JAR artifacts uses: actions/upload-artifact@v4 with: @@ -96,212 +94,211 @@ jobs: build_id: ${{ steps.test.outputs.build_id }} steps: - - uses: actions/checkout@v4 - - - name: Download JAR artifacts - uses: actions/download-artifact@v4 - with: - name: java-spring-jar-${{ github.run_number }} - path: java-spring/build/libs/ - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '17' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 - - - name: Create .env file (root) - run: | - echo "DITTO_APP_ID=${{ secrets.DITTO_APP_ID }}" > .env - echo "DITTO_PLAYGROUND_TOKEN=${{ secrets.DITTO_PLAYGROUND_TOKEN }}" >> .env - echo "DITTO_AUTH_URL=${{ secrets.DITTO_AUTH_URL }}" >> .env - echo "DITTO_WEBSOCKET_URL=${{ secrets.DITTO_WEBSOCKET_URL }}" >> .env - - - name: Install BrowserStack Local binary - run: | - curl -O "https://www.browserstack.com/browserstack-local/BrowserStackLocal-darwin-x64.zip" - unzip BrowserStackLocal-darwin-x64.zip - chmod +x BrowserStackLocal - - - name: Start BrowserStack Local tunnel - run: | - echo "Starting BrowserStack Local tunnel..." - nohup ./BrowserStackLocal --key "${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ - --daemon-mode > browserstack-local.log 2>&1 & - - # Wait for tunnel to establish - TIMEOUT=60 - ELAPSED=0 - - while [ $ELAPSED -lt $TIMEOUT ]; do - if [ -f browserstack-local.log ] && grep -q "You can now access your local server(s) in our remote browser" browserstack-local.log; then - echo "BrowserStack Local tunnel established" - exit 0 - fi - if [ -f browserstack-local.log ] && grep -q -i "error\|failed\|unable" browserstack-local.log; then - echo "BrowserStack Local tunnel failed:" - cat browserstack-local.log - exit 1 - fi - sleep 5 - ELAPSED=$((ELAPSED + 5)) - done - - echo "BrowserStack Local tunnel timeout after ${TIMEOUT}s" - [ -f browserstack-local.log ] && cat browserstack-local.log - exit 1 - - - name: Get BrowserStack build info - id: build-info - uses: ./.github/actions/generate-browserstack-names - with: - - - name: Create BrowserStack config - working-directory: java-spring - run: | - # Load platforms from centralized config and convert to YAML format - PLATFORMS=$(yq eval '.["java-spring"].platforms[] | " - os: \(.os)\n osVersion: \"\(.osVersion)\"\n browserName: \(.browserName)\n browserVersion: \(.browserVersion)"' ../.github/browserstack-devices.yml) - - cat > browserstack.yml << EOF - userName: ${{ secrets.BROWSERSTACK_USERNAME }} - accessKey: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} - projectName: ${{ steps.build-info.outputs.project-name }} - buildName: ${{ steps.build-info.outputs.build-name }} - platforms: - $PLATFORMS - browserstackLocal: true - debug: true - video: true - parallelsPerPlatform: 1 - EOF - - - name: Start Spring Boot app in background - working-directory: java-spring - env: - DITTO_APP_ID: ${{ secrets.DITTO_APP_ID }} - DITTO_PLAYGROUND_TOKEN: ${{ secrets.DITTO_PLAYGROUND_TOKEN }} - DITTO_AUTH_URL: ${{ secrets.DITTO_AUTH_URL }} - DITTO_WEBSOCKET_URL: ${{ secrets.DITTO_WEBSOCKET_URL }} - DITTO_ENABLE_CLOUD_SYNC: true - run: | - nohup java -jar build/libs/*.jar \ - --server.port=8080 \ - --spring.profiles.active=test > app.log 2>&1 & - echo $! > app.pid - - # Wait for application to be ready - echo "Waiting for Spring Boot app to start..." - for i in {1..30}; do - if curl -f http://localhost:8080 >/dev/null 2>&1; then - echo "Spring Boot app is ready" - break - fi - sleep 2 - done - - - name: Seed and execute Selenium tests on BrowserStack cloud browsers - id: test - uses: nick-fields/retry@v3 - env: - BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} - BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} - BROWSERSTACK_LOCAL: true - with: - max_attempts: 5 - timeout_minutes: 20 - retry_wait_seconds: 900 - command: | - # Seed test task to Ditto Cloud - echo "Seeding test task to Ditto Cloud..." - TIMESTAMP=$(date +%s) - INVERTED_TIMESTAMP=$((9999999999 - TIMESTAMP)) - SEED_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \ - -H 'Content-type: application/json' \ - -H "Authorization: Bearer ${{ secrets.DITTO_API_KEY }}" \ - -d "{ - \"statement\": \"INSERT INTO tasks DOCUMENTS (:newTask) ON ID CONFLICT DO UPDATE\", - \"args\": { - \"newTask\": { - \"_id\": \"${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}\", - \"title\": \"${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}\", - \"done\": false, - \"deleted\": false - } - } - }" \ - "https://${{ secrets.DITTO_API_URL }}/api/v4/store/execute") - - HTTP_CODE=$(echo "$SEED_RESPONSE" | tail -n1) - BODY=$(echo "$SEED_RESPONSE" | sed '$d') + - uses: actions/checkout@v4 - if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 201 ]; then - TASK_TITLE="${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}" - echo "Seeded task: $TASK_TITLE" - else - echo "Error: Failed to seed task. HTTP Status: $HTTP_CODE" - echo "Response: $BODY" - exit 1 - fi + - name: Download JAR artifacts + uses: actions/download-artifact@v4 + with: + name: java-spring-jar-${{ github.run_number }} + path: java-spring/build/libs/ - # Export as environment variable (for System.getenv()) - export DITTO_CLOUD_TASK_TITLE="$TASK_TITLE" + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" - # Run BrowserStack Selenium tests - cd java-spring - ./gradlew test --tests "*TaskVisibilityIntegrationTest.shouldPassWithExistingTask" \ - -DBROWSERSTACK_USERNAME="${{ secrets.BROWSERSTACK_USERNAME }}" \ - -DBROWSERSTACK_ACCESS_KEY="${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ - -DBROWSERSTACK_LOCAL=true \ - -DDITTO_CLOUD_TASK_TITLE="$TASK_TITLE" \ - --info + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 - # Query BrowserStack API to get the build ID - echo "Fetching build ID from BrowserStack..." - BUILDS_RESPONSE=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ - "https://api.browserstack.com/automate/builds.json?limit=1") + - name: Create .env file (root) + run: | + echo "DITTO_APP_ID=${{ secrets.DITTO_APP_ID }}" > .env + echo "DITTO_PLAYGROUND_TOKEN=${{ secrets.DITTO_PLAYGROUND_TOKEN }}" >> .env + echo "DITTO_AUTH_URL=${{ secrets.DITTO_AUTH_URL }}" >> .env + echo "DITTO_WEBSOCKET_URL=${{ secrets.DITTO_WEBSOCKET_URL }}" >> .env - BUILD_ID=$(echo "$BUILDS_RESPONSE" | yq eval '.[0].hashed_id' -) + - name: Install BrowserStack Local binary + run: | + curl -O "https://www.browserstack.com/browserstack-local/BrowserStackLocal-darwin-x64.zip" + unzip BrowserStackLocal-darwin-x64.zip + chmod +x BrowserStackLocal - if [ "$BUILD_ID" != "null" ] && [ -n "$BUILD_ID" ]; then - echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT - echo "✅ Build ID: $BUILD_ID" - else - echo "⚠️ Could not retrieve build ID from BrowserStack API" + - name: Start BrowserStack Local tunnel + run: | + echo "Starting BrowserStack Local tunnel..." + nohup ./BrowserStackLocal --key "${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + --daemon-mode > browserstack-local.log 2>&1 & + + # Wait for tunnel to establish + TIMEOUT=60 + ELAPSED=0 + + while [ $ELAPSED -lt $TIMEOUT ]; do + if [ -f browserstack-local.log ] && grep -q "You can now access your local server(s) in our remote browser" browserstack-local.log; then + echo "BrowserStack Local tunnel established" + exit 0 + fi + if [ -f browserstack-local.log ] && grep -q -i "error\|failed\|unable" browserstack-local.log; then + echo "BrowserStack Local tunnel failed:" + cat browserstack-local.log + exit 1 + fi + sleep 5 + ELAPSED=$((ELAPSED + 5)) + done + + echo "BrowserStack Local tunnel timeout after ${TIMEOUT}s" + [ -f browserstack-local.log ] && cat browserstack-local.log + exit 1 + + - name: Get BrowserStack build info + id: build-info + uses: ./.github/actions/generate-browserstack-names + + - name: Create BrowserStack config + working-directory: java-spring + run: | + # Load platforms from centralized config and convert to YAML format + PLATFORMS=$(yq eval '.["java-spring"].platforms[] | " - os: \(.os)\n osVersion: \"\(.osVersion)\"\n browserName: \(.browserName)\n browserVersion: \(.browserVersion)"' ../.github/browserstack-devices.yml) + + cat > browserstack.yml << EOF + userName: ${{ secrets.BROWSERSTACK_USERNAME }} + accessKey: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + projectName: ${{ steps.build-info.outputs.project-name }} + buildName: ${{ steps.build-info.outputs.build-name }} + platforms: + $PLATFORMS + browserstackLocal: true + debug: true + video: true + parallelsPerPlatform: 1 + EOF + + - name: Start Spring Boot app in background + working-directory: java-spring + env: + DITTO_APP_ID: ${{ secrets.DITTO_APP_ID }} + DITTO_PLAYGROUND_TOKEN: ${{ secrets.DITTO_PLAYGROUND_TOKEN }} + DITTO_AUTH_URL: ${{ secrets.DITTO_AUTH_URL }} + DITTO_WEBSOCKET_URL: ${{ secrets.DITTO_WEBSOCKET_URL }} + DITTO_ENABLE_CLOUD_SYNC: true + run: | + nohup java -jar build/libs/*.jar \ + --server.port=8080 \ + --spring.profiles.active=test > app.log 2>&1 & + echo $! > app.pid + + # Wait for application to be ready + echo "Waiting for Spring Boot app to start..." + for i in {1..30}; do + if curl -f http://localhost:8080 >/dev/null 2>&1; then + echo "Spring Boot app is ready" + break + fi + sleep 2 + done + + - name: Seed and execute Selenium tests on BrowserStack cloud browsers + id: test + uses: nick-fields/retry@v3 + env: + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + BROWSERSTACK_LOCAL: true + with: + max_attempts: 5 + timeout_minutes: 20 + retry_wait_seconds: 900 + command: | + # Seed test task to Ditto Cloud + echo "Seeding test task to Ditto Cloud..." + TIMESTAMP=$(date +%s) + INVERTED_TIMESTAMP=$((9999999999 - TIMESTAMP)) + SEED_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \ + -H 'Content-type: application/json' \ + -H "Authorization: Bearer ${{ secrets.DITTO_API_KEY }}" \ + -d "{ + \"statement\": \"INSERT INTO tasks DOCUMENTS (:newTask) ON ID CONFLICT DO UPDATE\", + \"args\": { + \"newTask\": { + \"_id\": \"${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}\", + \"title\": \"${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}\", + \"done\": false, + \"deleted\": false + } + } + }" \ + "https://${{ secrets.DITTO_API_URL }}/api/v4/store/execute") + + HTTP_CODE=$(echo "$SEED_RESPONSE" | tail -n1) + BODY=$(echo "$SEED_RESPONSE" | sed '$d') + + if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 201 ]; then + TASK_TITLE="${INVERTED_TIMESTAMP}_java-spring_ci_test_${{ github.run_id }}_${{ github.run_number }}" + echo "Seeded task: $TASK_TITLE" + else + echo "Error: Failed to seed task. HTTP Status: $HTTP_CODE" + echo "Response: $BODY" + exit 1 + fi + + # Export as environment variable (for System.getenv()) + export DITTO_CLOUD_TASK_TITLE="$TASK_TITLE" + + # Run BrowserStack Selenium tests + cd java-spring + ./gradlew test --tests "*TaskVisibilityIntegrationTest.shouldPassWithExistingTask" \ + -DBROWSERSTACK_USERNAME="${{ secrets.BROWSERSTACK_USERNAME }}" \ + -DBROWSERSTACK_ACCESS_KEY="${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + -DBROWSERSTACK_LOCAL=true \ + -DDITTO_CLOUD_TASK_TITLE="$TASK_TITLE" \ + --info + + # Query BrowserStack API to get the build ID + echo "Fetching build ID from BrowserStack..." + BUILDS_RESPONSE=$(curl -s -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \ + "https://api.browserstack.com/automate/builds.json?limit=1") + + BUILD_ID=$(echo "$BUILDS_RESPONSE" | yq eval '.[0].hashed_id' -) + + if [ "$BUILD_ID" != "null" ] && [ -n "$BUILD_ID" ]; then + echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT + echo "✅ Build ID: $BUILD_ID" + else + echo "⚠️ Could not retrieve build ID from BrowserStack API" + fi + + - name: Stop Spring Boot app + if: always() + working-directory: java-spring + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid fi - - name: Stop Spring Boot app - if: always() - working-directory: java-spring - run: | - if [ -f app.pid ]; then - kill $(cat app.pid) || true - rm app.pid - fi - - - name: Stop BrowserStack Local tunnel - if: always() - run: pkill -f "BrowserStackLocal" || true - - - name: Upload test reports - if: always() - uses: actions/upload-artifact@v4 - with: - name: browserstack-test-reports-${{ github.run_number }} - path: java-spring/build/reports/tests/ - retention-days: 1 - - - name: Upload app logs - if: always() - uses: actions/upload-artifact@v4 - with: - name: spring-boot-logs-${{ github.run_number }} - path: | - java-spring/app.log - browserstack-local.log - retention-days: 1 + - name: Stop BrowserStack Local tunnel + if: always() + run: pkill -f "BrowserStackLocal" || true + + - name: Upload test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: browserstack-test-reports-${{ github.run_number }} + path: java-spring/build/reports/tests/ + retention-days: 1 + + - name: Upload app logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: spring-boot-logs-${{ github.run_number }} + path: | + java-spring/app.log + browserstack-local.log + retention-days: 1 summary: name: CI Report @@ -310,34 +307,34 @@ jobs: if: always() steps: - - name: Report Results - run: | - echo "## ☕ Java Spring CI" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # Overall status - if [[ "${{ needs.lint.result }}" == "success" && \ - "${{ needs.build.result }}" == "success" && \ - "${{ needs.browserstack-test.result }}" == "success" ]]; then - echo "**Overall Status:** ✅ All checks passed" >> $GITHUB_STEP_SUMMARY - else - echo "**Overall Status:** ❌ Failed" >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY - echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Lint | ${{ needs.lint.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Build | ${{ needs.build.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "| BrowserStack Tests | ${{ needs.browserstack-test.result == 'success' && '✅ Passed' || (needs.browserstack-test.result == 'skipped' && '⏭️ Skipped') || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - # BrowserStack link - if [[ "${{ needs.browserstack-test.result }}" != "skipped" ]] && [ -n "${{ needs.browserstack-test.outputs.build_id }}" ]; then - echo "### BrowserStack Session" >> $GITHUB_STEP_SUMMARY + - name: Report Results + run: | + echo "## ☕ Java Spring CI" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "🔗 [View Test Results](https://automate.browserstack.com/dashboard/v2/builds/${{ needs.browserstack-test.outputs.build_id }}/)" >> $GITHUB_STEP_SUMMARY + + # Overall status + if [[ "${{ needs.lint.result }}" == "success" && \ + "${{ needs.build.result }}" == "success" && \ + "${{ needs.browserstack-test.result }}" == "success" ]]; then + echo "**Overall Status:** ✅ All checks passed" >> $GITHUB_STEP_SUMMARY + else + echo "**Overall Status:** ❌ Failed" >> $GITHUB_STEP_SUMMARY + fi echo "" >> $GITHUB_STEP_SUMMARY - echo "**Tested Browser:**" >> $GITHUB_STEP_SUMMARY - echo "- Chrome Latest (Windows 11)" >> $GITHUB_STEP_SUMMARY - fi + + echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY + echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Lint | ${{ needs.lint.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| Build | ${{ needs.build.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "| BrowserStack Tests | ${{ needs.browserstack-test.result == 'success' && '✅ Passed' || (needs.browserstack-test.result == 'skipped' && '⏭️ Skipped') || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # BrowserStack link + if [[ "${{ needs.browserstack-test.result }}" != "skipped" ]] && [ -n "${{ needs.browserstack-test.outputs.build_id }}" ]; then + echo "### BrowserStack Session" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "🔗 [View Test Results](https://automate.browserstack.com/dashboard/v2/builds/${{ needs.browserstack-test.outputs.build_id }}/)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Tested Browser:**" >> $GITHUB_STEP_SUMMARY + echo "- Chrome Latest (Windows 11)" >> $GITHUB_STEP_SUMMARY + fi From 9a0cd30aa3a547fa17b31b8e78382998151069cf Mon Sep 17 00:00:00 2001 From: Vincent Ahrend Date: Fri, 31 Oct 2025 11:45:29 +0100 Subject: [PATCH 3/4] feat: add GitHub Actions workflow for linting --- .github/workflows/lint-gha-workflow.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/lint-gha-workflow.yml diff --git a/.github/workflows/lint-gha-workflow.yml b/.github/workflows/lint-gha-workflow.yml new file mode 100644 index 000000000..39cdb1c2b --- /dev/null +++ b/.github/workflows/lint-gha-workflow.yml @@ -0,0 +1,17 @@ +name: Lint GitHub Actions workflows +on: [push, pull_request] + +jobs: + actionlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download actionlint + id: get_actionlint + run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) + shell: bash + + - name: Check workflow files + run: ${{ steps.get_actionlint.outputs.executable }} -color + shell: bash From c5f108383639b458e2596d15d71d6f4332ba4d29 Mon Sep 17 00:00:00 2001 From: Vincent Ahrend Date: Fri, 31 Oct 2025 12:45:28 +0100 Subject: [PATCH 4/4] Revert "feat: add GitHub Actions workflow for linting" This reverts commit 9a0cd30aa3a547fa17b31b8e78382998151069cf. --- .github/workflows/lint-gha-workflow.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/lint-gha-workflow.yml diff --git a/.github/workflows/lint-gha-workflow.yml b/.github/workflows/lint-gha-workflow.yml deleted file mode 100644 index 39cdb1c2b..000000000 --- a/.github/workflows/lint-gha-workflow.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Lint GitHub Actions workflows -on: [push, pull_request] - -jobs: - actionlint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Download actionlint - id: get_actionlint - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) - shell: bash - - - name: Check workflow files - run: ${{ steps.get_actionlint.outputs.executable }} -color - shell: bash