Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a6b7767
feat: Add comprehensive Android CI/CD pipelines with BrowserStack int…
teodorciuraru Sep 1, 2025
db66742
fix: Standardize android-cpp-browserstack workflow name to match othe…
teodorciuraru Sep 1, 2025
d71330a
fix: Resolve Android CI pipeline issues and standardize with RN patterns
teodorciuraru Sep 1, 2025
a1a9a6f
feat: Restructure Android CI to match React Native pattern and fix in…
teodorciuraru Sep 1, 2025
df1bb4d
fix: Fix Android BrowserStack integration test failures
teodorciuraru Sep 1, 2025
45871ca
fix: Android CPP TasksUITest device-specific failures on Samsung Gala…
teodorciuraru Sep 1, 2025
6101e75
refactor: extract reusable composite actions for Android CI
teodorciuraru Sep 1, 2025
111edaa
refactor: complete Android workflow refactoring with composite actions
teodorciuraru Sep 1, 2025
8c2d380
fix: android-cpp-ci.yml workflow syntax error
teodorciuraru Sep 1, 2025
338f3b4
refactor: extract Ditto test document insertion into composite action
teodorciuraru Sep 2, 2025
e4d4a4b
feat: rewrite Android integration tests to verify Ditto sync
teodorciuraru Sep 2, 2025
18c6b1a
feat: add Java Spring CI pipeline with SDK-based integration tests
teodorciuraru Sep 2, 2025
4362dad
feat: add Java Spring CI workflow and include in PR checks
teodorciuraru Sep 2, 2025
6982c17
fix: exclude Java Spring integration tests from CI build
teodorciuraru Sep 2, 2025
f81f730
fix: exclude Java Spring integration tests from standalone CI workflow
teodorciuraru Sep 2, 2025
f8d83ea
fix: use specific test class for Java Spring CI instead of exclusion …
teodorciuraru Sep 2, 2025
fcf33c5
fix: update Android CPP integration tests to match JavaScript pattern
teodorciuraru Sep 2, 2025
4554b0d
feat: align Android integration tests with JavaScript HTTP API pattern
teodorciuraru Sep 2, 2025
c96c052
fix: update Java Spring CI test pattern for better CI compatibility
teodorciuraru Sep 2, 2025
6bc3580
fix: implement proper sync verification in all Android integration tests
teodorciuraru Sep 2, 2025
c009b1f
fix: simplify Java Spring test to avoid Spring Boot context loading i…
teodorciuraru Sep 2, 2025
1cf6af3
fix: remove unit tests from BrowserStack workflows and fix Java Sprin…
teodorciuraru Sep 2, 2025
1f7d8ff
fix: add minimal .env file creation for Java Spring CI
teodorciuraru Sep 2, 2025
9127b43
fix: resolve Android permission issues in BrowserStack integration tests
teodorciuraru Sep 2, 2025
c504ffa
fix: redesign Android integration tests to use UI-based verification
teodorciuraru Sep 2, 2025
935d80d
fix: redesign Android integration tests for BrowserStack compatibility
teodorciuraru Sep 2, 2025
00d652d
feat: add Java Spring BrowserStack integration workflow
teodorciuraru Sep 2, 2025
d51cd4b
fix: Java Spring BrowserStack workflow - use Gradle instead of Maven
teodorciuraru Sep 2, 2025
0a0fa94
fix: correct JAR filename in Java Spring BrowserStack workflow
teodorciuraru Sep 2, 2025
80a0fc7
fix: install libffi-dev for Ditto SDK native library loading
teodorciuraru Sep 2, 2025
85402de
feat: add CI-safe configuration for Java Spring BrowserStack testing
teodorciuraru Sep 2, 2025
5210b0d
fix: make DittoConfigRestController conditional on ditto.enabled prop…
teodorciuraru Sep 2, 2025
7d3d6b6
fix: implement proper BrowserStack Local tunnel for Java Spring tests
teodorciuraru Sep 3, 2025
5abd1a7
fix: improve BrowserStack Local tunnel reliability with better verifi…
teodorciuraru Sep 3, 2025
08a1340
fix: use exact BrowserStack Local daemon pattern from working JS refe…
teodorciuraru Sep 3, 2025
435b758
fix: remove conflicting BrowserStack Local status check
teodorciuraru Sep 3, 2025
f440439
feat: improve BrowserStack workflows with unique project names and en…
teodorciuraru Sep 3, 2025
b25cddb
fix: resolve critical BrowserStack workflow issues
teodorciuraru Sep 3, 2025
6885d70
fix: improve BrowserStack Local tunnel debugging and connectivity
teodorciuraru Sep 3, 2025
73ee89e
fix: add 64-bit ABI support for Pixel 8 and modern Android devices
teodorciuraru Sep 3, 2025
d10f8f2
refactor: replace complex Android tests with simple sync verification…
teodorciuraru Sep 3, 2025
457f00b
feat: implement inline HTTP API seeding matching JavaScript pattern
teodorciuraru Sep 3, 2025
6b0707f
feat: complete 6-step flow for all 3 Android apps with inline seeding
teodorciuraru Sep 3, 2025
a9a71cf
fix: improve Android tests with scrolling and dialog handling, update…
teodorciuraru Sep 3, 2025
71bd2fe
fix: add explicit UIAutomator dependency to all Android apps
teodorciuraru Sep 3, 2025
2d6baaf
fix: implement aggressive location permission dialog dismissal
teodorciuraru Sep 3, 2025
63bc3d2
refactor: reset Java Spring BrowserStack workflow to clean, simple pa…
teodorciuraru Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/actions/android-sdk-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: 'Android SDK Setup'
description: 'Setup Java and Android SDK for any Android project (React Native, Flutter, Native)'
inputs:
java-version:
description: 'Java version to use'
required: false
default: '17'
java-distribution:
description: 'Java distribution to use'
required: false
default: 'temurin'

runs:
using: 'composite'
steps:
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
distribution: ${{ inputs.java-distribution }}

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
210 changes: 210 additions & 0 deletions .github/actions/browserstack-android-apk/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
name: 'BrowserStack Android APK Test'
description: 'Upload APKs to BrowserStack and run tests on real Android devices'
inputs:
working-directory:
description: 'Working directory containing the Android project'
required: true
project-name:
description: 'Project name for BrowserStack (e.g., "Ditto Android Java")'
required: true
project-type:
description: 'Project type identifier (e.g., "android-java", "android-kotlin")'
required: true
app-apk-path:
description: 'Path to the app APK file'
required: true
test-apk-path:
description: 'Path to the test APK file'
required: true
browserstack-username:
description: 'BrowserStack username'
required: true
browserstack-access-key:
description: 'BrowserStack access key'
required: true
ditto-api-key:
description: 'Ditto API key for test document insertion'
required: true
ditto-api-url:
description: 'Ditto API URL'
required: true
github-test-doc-id:
description: 'GitHub test document ID'
required: true

runs:
using: 'composite'
steps:
- name: Upload APKs to BrowserStack
id: upload
shell: bash
run: |
# Upload app APK
echo "Uploading app APK..."
APP_UPLOAD_RESPONSE=$(curl -u "${{ inputs.browserstack-username }}:${{ inputs.browserstack-access-key }}" \
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
-F "file=@${{ inputs.app-apk-path }}" \
-F "custom_id=ditto-${{ inputs.project-type }}-app-${{ github.run_id }}")

echo "App upload response: $APP_UPLOAD_RESPONSE"
APP_URL=$(echo $APP_UPLOAD_RESPONSE | jq -r .app_url)

if [ "$APP_URL" = "null" ] || [ -z "$APP_URL" ]; then
echo "Error: Failed to upload app APK"
echo "Response: $APP_UPLOAD_RESPONSE"
exit 1
fi

echo "app_url=$APP_URL" >> $GITHUB_OUTPUT
echo "App uploaded successfully: $APP_URL"

# Upload test APK
echo "Uploading test APK..."
TEST_UPLOAD_RESPONSE=$(curl -u "${{ inputs.browserstack-username }}:${{ inputs.browserstack-access-key }}" \
-X POST "https://api-cloud.browserstack.com/app-automate/espresso/test-suite" \
-F "file=@${{ inputs.test-apk-path }}" \
-F "custom_id=ditto-${{ inputs.project-type }}-test-${{ github.run_id }}")

echo "Test upload response: $TEST_UPLOAD_RESPONSE"
TEST_URL=$(echo $TEST_UPLOAD_RESPONSE | jq -r .test_url)

if [ "$TEST_URL" = "null" ] || [ -z "$TEST_URL" ]; then
echo "Error: Failed to upload test APK"
echo "Response: $TEST_UPLOAD_RESPONSE"
exit 1
fi

echo "test_url=$TEST_URL" >> $GITHUB_OUTPUT
echo "Test APK uploaded successfully: $TEST_URL"

- name: Execute tests on BrowserStack
id: test
shell: bash
run: |
# Validate inputs
APP_URL="${{ steps.upload.outputs.app_url }}"
TEST_URL="${{ steps.upload.outputs.test_url }}"

echo "App URL: $APP_URL"
echo "Test URL: $TEST_URL"

if [ -z "$APP_URL" ] || [ "$APP_URL" = "null" ]; then
echo "Error: No valid app URL available"
exit 1
fi

if [ -z "$TEST_URL" ] || [ "$TEST_URL" = "null" ]; then
echo "Error: No valid test URL available"
exit 1
fi

# Create test execution request with diverse device configurations
BUILD_RESPONSE=$(curl -u "${{ inputs.browserstack-username }}:${{ inputs.browserstack-access-key }}" \
-X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \
-H "Content-Type: application/json" \
-d "{
\"app\": \"$APP_URL\",
\"testSuite\": \"$TEST_URL\",
\"devices\": [
\"Google Pixel 8-14.0\",
\"Samsung Galaxy S23-13.0\",
\"Google Pixel 6-12.0\",
\"OnePlus 9-11.0\"
],
\"projectName\": \"${{ inputs.project-name }}\",
\"buildName\": \"Build #${{ github.run_number }}\",
\"buildTag\": \"${{ github.ref_name }}\",
\"deviceLogs\": true,
\"video\": true,
\"networkLogs\": true,
\"autoGrantPermissions\": true,
\"testAnnotations\": {
\"data\": {
\"github_run_id\": \"${{ github.run_id }}\",
\"github_test_doc_id\": \"${{ inputs.github-test-doc-id }}\",
\"project_type\": \"${{ inputs.project-type }}\"
}
},
\"instrumentationLogs\": true,
\"testRunnerClass\": \"androidx.test.runner.AndroidJUnitRunner\",
\"testRunnerArgs\": {
\"github_run_id\": \"${{ github.run_id }}\",
\"github_test_doc_id\": \"${{ inputs.github-test-doc-id }}\"
}
}")

echo "BrowserStack API Response:"
echo "$BUILD_RESPONSE"

BUILD_ID=$(echo "$BUILD_RESPONSE" | jq -r .build_id)

if [ "$BUILD_ID" = "null" ] || [ -z "$BUILD_ID" ]; then
echo "Error: Failed to create BrowserStack build"
echo "Response: $BUILD_RESPONSE"
exit 1
fi

echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT
echo "Build started with ID: $BUILD_ID"

- name: Wait for BrowserStack tests to complete
shell: bash
run: |
BUILD_ID="${{ steps.test.outputs.build_id }}"

if [ "$BUILD_ID" = "null" ] || [ -z "$BUILD_ID" ]; then
echo "Error: No valid BUILD_ID available. Skipping test monitoring."
exit 1
fi

MAX_WAIT_TIME=1800 # 30 minutes
CHECK_INTERVAL=30 # Check every 30 seconds
ELAPSED=0

while [ $ELAPSED -lt $MAX_WAIT_TIME ]; do
BUILD_STATUS_RESPONSE=$(curl -s -u "${{ inputs.browserstack-username }}:${{ inputs.browserstack-access-key }}" \
"https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID")

BUILD_STATUS=$(echo "$BUILD_STATUS_RESPONSE" | jq -r .status)

if [ "$BUILD_STATUS" = "null" ] || [ -z "$BUILD_STATUS" ]; then
echo "Error getting build status. Response: $BUILD_STATUS_RESPONSE"
sleep $CHECK_INTERVAL
ELAPSED=$((ELAPSED + CHECK_INTERVAL))
continue
fi

echo "Build status: $BUILD_STATUS (elapsed: ${ELAPSED}s)"

if [ "$BUILD_STATUS" = "done" ] || [ "$BUILD_STATUS" = "failed" ] || [ "$BUILD_STATUS" = "error" ] || [ "$BUILD_STATUS" = "passed" ] || [ "$BUILD_STATUS" = "completed" ]; then
echo "Build completed with status: $BUILD_STATUS"
break
fi

sleep $CHECK_INTERVAL
ELAPSED=$((ELAPSED + CHECK_INTERVAL))
done

# Get final results
FINAL_RESULT=$(curl -s -u "${{ inputs.browserstack-username }}:${{ inputs.browserstack-access-key }}" \
"https://api-cloud.browserstack.com/app-automate/espresso/v2/builds/$BUILD_ID")

echo "Final build result:"
echo "$FINAL_RESULT" | jq .

if echo "$FINAL_RESULT" | jq -e .devices > /dev/null 2>&1; then
BUILD_STATUS=$(echo "$FINAL_RESULT" | jq -r .status)
if [ "$BUILD_STATUS" != "passed" ]; then
echo "Build failed with status: $BUILD_STATUS"
FAILED_TESTS=$(echo "$FINAL_RESULT" | jq -r '.devices[] | select(.sessions[].status != "passed") | .device')
if [ -n "$FAILED_TESTS" ]; then
echo "Tests failed on devices: $FAILED_TESTS"
fi
exit 1
else
echo "All tests passed successfully!"
fi
else
echo "Warning: Could not parse final results"
echo "Raw response: $FINAL_RESULT"
fi
37 changes: 37 additions & 0 deletions .github/actions/ditto-env-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: 'Ditto Environment Setup'
description: 'Create .env file with Ditto credentials for any Ditto project'
inputs:
use-secrets:
description: 'Whether to use secrets or test values for environment variables'
required: false
default: 'false'
ditto-app-id:
description: 'Ditto App ID (when using secrets)'
required: false
ditto-playground-token:
description: 'Ditto Playground Token (when using secrets)'
required: false
ditto-auth-url:
description: 'Ditto Auth URL (when using secrets)'
required: false
ditto-websocket-url:
description: 'Ditto WebSocket URL (when using secrets)'
required: false

runs:
using: 'composite'
steps:
- name: Create .env file
shell: bash
run: |
if [ "${{ inputs.use-secrets }}" = "true" ]; then
echo "DITTO_APP_ID=${{ inputs.ditto-app-id }}" > .env
echo "DITTO_PLAYGROUND_TOKEN=${{ inputs.ditto-playground-token }}" >> .env
echo "DITTO_AUTH_URL=${{ inputs.ditto-auth-url }}" >> .env
echo "DITTO_WEBSOCKET_URL=${{ inputs.ditto-websocket-url }}" >> .env
else
echo "DITTO_APP_ID=test_app_id" > .env
echo "DITTO_PLAYGROUND_TOKEN=test_playground_token" >> .env
echo "DITTO_AUTH_URL=https://auth.example.com" >> .env
echo "DITTO_WEBSOCKET_URL=wss://websocket.example.com" >> .env
fi
53 changes: 53 additions & 0 deletions .github/actions/ditto-test-document-insert/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: 'Ditto Test Document Insert'
description: 'Insert a GitHub test document into Ditto Cloud for integration testing'
inputs:
project-type:
description: 'Project type identifier (e.g., "android-java", "android-kotlin", "flutter")'
required: true
ditto-api-key:
description: 'Ditto API key for document insertion'
required: true
ditto-api-url:
description: 'Ditto API URL'
required: true

runs:
using: 'composite'
steps:
- name: Insert test document into Ditto Cloud
shell: bash
run: |
# Use GitHub run ID to create deterministic document ID
DOC_ID="github_${{ inputs.project-type }}_${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER}"
TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")

# Insert document using curl with correct JSON structure
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
-H 'Content-type: application/json' \
-H "Authorization: Bearer ${{ inputs.ditto-api-key }}" \
-d "{
\"statement\": \"INSERT INTO tasks DOCUMENTS (:newTask) ON ID CONFLICT DO UPDATE\",
\"args\": {
\"newTask\": {
\"_id\": \"${DOC_ID}\",
\"title\": \"GitHub Test Task ${{ inputs.project-type }} ${GITHUB_RUN_ID}\",
\"done\": false,
\"deleted\": false
}
}
}" \
"https://${{ inputs.ditto-api-url }}/api/v4/store/execute")

# Extract HTTP status code and response body
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)

# Check if insertion was successful
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 201 ]; then
echo "βœ“ Successfully inserted test document with ID: ${DOC_ID}"
echo "GITHUB_TEST_DOC_ID=${DOC_ID}" >> $GITHUB_ENV
else
echo "❌ Failed to insert document. HTTP Status: $HTTP_CODE"
echo "Response: $BODY"
exit 1
fi
15 changes: 15 additions & 0 deletions .github/actions/gradle-cache/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: 'Gradle Cache'
description: 'Cache Gradle dependencies for faster builds'

runs:
using: 'composite'
steps:
- 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-
33 changes: 33 additions & 0 deletions .github/actions/java-maven-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: 'Java and Maven Setup'
description: 'Sets up Java JDK and Maven for Spring Boot projects'

inputs:
java-version:
description: 'Java version to use'
required: false
default: '17'
maven-version:
description: 'Maven version to use'
required: false
default: '3.9.6'

runs:
using: 'composite'
steps:
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'

- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Set up Maven
uses: stCarolas/setup-maven@v5
with:
maven-version: ${{ inputs.maven-version }}
Loading
Loading