diff --git a/.github/docker/simple-server.compose.yml b/.github/docker/simple-server.compose.yml index c4576f81c81..9e190437c58 100644 --- a/.github/docker/simple-server.compose.yml +++ b/.github/docker/simple-server.compose.yml @@ -15,7 +15,12 @@ services: - "6379" server: - image: simpledotorg/server:latest + build: + context: https://github.com/simpledotorg/simple-server.git + dockerfile: ./.docker/dev.Dockerfile + image: simple-server:latest + volumes: + - .:/myapp command: bash -c "rm -f tmp/pids/server.pid && bundle exec rake db:setup; bundle exec rails s -p 3000 -b '0.0.0.0'" expose: - "3000" diff --git a/.github/scripts/wait_for_docker_server.sh b/.github/scripts/wait_for_docker_server.sh new file mode 100755 index 00000000000..45babb6ba24 --- /dev/null +++ b/.github/scripts/wait_for_docker_server.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +docker network inspect backend + +url="http://localhost:8420" +timeout_in_seconds=3600 # 60 minutes in seconds + +start_time=$(date +%s) + +while true; do + response_code=$(curl -s -o /dev/null -w "%{http_code}" "$url") + + if [ "$response_code" -eq 200 ]; then + echo "Success! Received 200 OK response." + break + else + echo "Failed, got $response_code as response code. Retrying..." + sleep 5 + + current_time=$(date +%s) + elapsed_time=$((current_time - start_time)) + + if [ "$elapsed_time" -ge "$timeout_in_seconds" ]; then + echo "Timeout reached. Exiting." + exit 1 + fi + fi +done diff --git a/.github/workflows/ci_checks.yml b/.github/workflows/ci_checks.yml index 99523e17ff4..0bdae21c3e7 100644 --- a/.github/workflows/ci_checks.yml +++ b/.github/workflows/ci_checks.yml @@ -5,166 +5,97 @@ on: branches: - release/* pull_request: - workflow_dispatch: - inputs: - simple_server_branch: - required: false - type: string - default: master - workflow_call: concurrency: group: ci-${{ github.head_ref }} cancel-in-progress: true jobs: - qa_lint: + verify_changelog_updated: runs-on: [ ubuntu-latest ] + if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@v4 - - - name: set up JDK - uses: actions/setup-java@v4 + - name: Checkout master + uses: actions/checkout@v4 with: - distribution: 'zulu' - java-version: 17 - cache: 'gradle' - - - name: QA Lint - run: ./gradlew --build-cache --no-daemon lintQaDebug - - qa_unit_tests: - runs-on: [ ubuntu-latest ] - steps: - - uses: actions/checkout@v4 + ref: master + path: master - - name: set up JDK - uses: actions/setup-java@v4 + - name: Checkout current + uses: actions/checkout@v4 with: - distribution: 'zulu' - java-version: 17 - cache: 'gradle' + path: current - - name: QA Unit Tests - run: ./gradlew --build-cache --no-daemon testQaDebugUnitTest + - name: Verify CHANGELOG was updated + run: current/.github/scripts/verify_file_was_changed.sh master/CHANGELOG.md current/CHANGELOG.md - generate_server_app_name: + verify_pr_description: runs-on: [ ubuntu-latest ] - outputs: - heroku_app_name: ${{ steps.generate-server-app-name.outputs.heroku_app_name }} + if: github.event_name == 'pull_request' steps: - - name: Checkout Android source - uses: actions/checkout@v4 - - - name: Generate server app name - id: generate-server-app-name - run: .github/scripts/generate_heroku_app_name.sh ${{ github.ref }} + - uses: actions/checkout@v4 + - name: Verify PR description + run: kotlinc -script ".github/scripts/PrCommentCheck.main.kts" "${{ github.event.pull_request.body }}" - create_server_on_heroku: - needs: generate_server_app_name + verify_room_schemas: runs-on: [ ubuntu-latest ] - outputs: - heroku_app_name: ${{ steps.create-server-on-heroku.outputs.heroku_app_name }} - heroku_app_url: ${{ steps.create-server-on-heroku.outputs.heroku_app_url }} - heroku_app_exists: ${{ steps.create-server-on-heroku.outputs.heroku_app_exists }} - env: - HEROKU_API_KEY: ${{ secrets.SERVICES_HEROKU_API_KEY }} steps: - - name: Checkout Android source + - name: Checkout master uses: actions/checkout@v4 with: - path: android-app + ref: master + path: master - - name: Checkout Server source + - name: Checkout current uses: actions/checkout@v4 with: - repository: simpledotorg/simple-server - fetch-depth: 0 # Full clone needed for Heroku deploys (https://devcenter.heroku.com/changelog-items/775) - path: server-app - ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.simple_server_branch || 'master' }} - - - name: Install Heroku CLI - if: steps.node-dependency-cache.outputs.cache-hit != 'true' - run: npm install heroku - - - name: Link Heroku CLI globally - run: npm link heroku + path: current - - name: Create server on Heroku - id: create-server-on-heroku - run: | - android-app/.github/scripts/create_heroku_app.sh \ - ${{ needs.generate_server_app_name.outputs.heroku_app_name }} \ - server-app + - name: Verify existing Room schemas are not modified + run: current/.github/scripts/compare_directory_contents.sh master/app/schemas/org.simple.clinic.AppDatabase current/app/schemas/org.simple.clinic.AppDatabase - deploy_server_on_heroku: - needs: [create_server_on_heroku] + verify_release_bundles: runs-on: [ ubuntu-latest ] - timeout-minutes: 60 - outputs: - heroku_app_name: ${{ steps.start-simple-server.outputs.heroku_app_name }} env: - HEROKU_API_KEY: ${{ secrets.SERVICES_HEROKU_API_KEY }} + TERM: dumb + ORG_GRADLE_PROJECT_KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + ORG_GRADLE_PROJECT_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} + ORG_GRADLE_PROJECT_KEY_ALIAS: ${{ secrets.KEY_ALIAS }} + strategy: + matrix: + buildType: [ 'Production' ] steps: - - name: Checkout Android source - uses: actions/checkout@v4 - with: - path: android-app + - uses: actions/checkout@v4 - - name: Checkout server app source - uses: actions/checkout@v4 + - name: set up JDK + uses: actions/setup-java@v4 with: - repository: simpledotorg/simple-server - fetch-depth: 0 # Full clone needed for Heroku deploys (https://devcenter.heroku.com/changelog-items/775) - path: server-app - ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.simple_server_branch || 'master' }} + distribution: 'zulu' + java-version: 17 + cache: 'gradle' - - name: Create node dependency hash - id: create_node_modules_hash - run: android-app/.github/scripts/compute_node_dependency_hash.sh + - name: Decrypt secrets + run: gpg --batch --yes --quiet --decrypt --passphrase=${{ secrets.KEYSTORE_PASSPHRASE }} --output release/simple.store release/simple.gpg - - name: Cache node modules - id: node-dependency-cache - uses: actions/cache@v4 - with: - path: | - node_modules - package-lock.json - key: ${{ runner.os }}-npm-${{ steps.create_node_modules_hash.outputs.node_dep_hash }} + - name: Build ${{ matrix.buildType }} Release bundle + run: | + ./gradlew \ + -PrunProguard=true \ + -PdefaultProguardFile=proguard-android.txt \ + -PsentryUploadProguard=false \ + bundle${{ matrix.buildType }}Release - - name: Install Heroku CLI - if: steps.node-dependency-cache.outputs.cache-hit != 'true' - run: npm install heroku + - name: Clean secrets + run: | + rm -f release/simple.store - - name: Link Heroku CLI globally - run: npm link heroku - - name: Install Heroku Buildpacks registry - run: heroku plugins:install buildpack-registry - - name: Install heroku buildpacks plugin - run: heroku plugins:install buildpacks - - name: Deploy the server on Heroku - id: start-simple-server - run: | - android-app/.github/scripts/setup_heroku_instance.sh \ - ${{ needs.create_server_on_heroku.outputs.heroku_app_name }} \ - ${{ env.HEROKU_API_KEY }} \ - ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.simple_server_branch || 'master' }} \ - server-app \ - android-app \ - ${{ needs.create_server_on_heroku.outputs.heroku_app_exists }} \ - ${{ secrets.HEROKU_SECRET_PROPERTIES }} - - - build_qa_android_tests_apk: - needs: create_server_on_heroku + qa_lint: runs-on: [ ubuntu-latest ] - timeout-minutes: 60 steps: - - name: Checkout Android source - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - name: set up JDK uses: actions/setup-java@v4 @@ -173,21 +104,25 @@ jobs: java-version: 17 cache: 'gradle' - - name: Build QA Test Artifacts - id: build-instrumented-tests - run: | - ./gradlew --build-cache --no-daemon -PmanifestEndpoint=${{ needs.create_server_on_heroku.outputs.heroku_app_url }}api/ assembleQaDebug assembleQaDebugAndroidTest + - name: QA Lint + run: ./gradlew --build-cache --no-daemon lintQaDebug - - name: Upload artifacts - uses: actions/upload-artifact@v4 + qa_unit_tests: + runs-on: [ ubuntu-latest ] + steps: + - uses: actions/checkout@v4 + + - name: set up JDK + uses: actions/setup-java@v4 with: - name: test-artifacts - path: app/build/outputs/apk + distribution: 'zulu' + java-version: 17 + cache: 'gradle' + + - name: QA Unit Tests + run: ./gradlew --build-cache --no-daemon testQaDebugUnitTest - # reactivecircus/android-emulator-runner@v2 requires MacOS to run on - # https://github.com/ReactiveCircus/android-emulator-runner qa_android_tests: - needs: [ deploy_server_on_heroku, build_qa_android_tests_apk ] runs-on: [ ubuntu-latest ] timeout-minutes: 60 env: @@ -200,9 +135,28 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm + - name: Checkout Android source uses: actions/checkout@v4 + - name: Start Simple Docker server + run: | + docker compose -f ".github/docker/simple-server.compose.yml" up -d + + - name: Wait for Docker server to be available + run: .github/scripts/wait_for_docker_server.sh + + - name: Get Docker server IP address + run: | + IP_ADDRESS=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' simple-server) + echo "Docker container IP address is: $IP_ADDRESS" + echo "DOCKER_IP=$IP_ADDRESS" >> $GITHUB_ENV + + - name: Replace IP address in network security config + run: | + sed -i "s/localhost/$DOCKER_IP/g" app/src/main/res/xml/network_config.xml + cat src/main/res/xml/network_config.xml + - name: Cache AVD uses: actions/cache@v4 id: avd-cache @@ -234,11 +188,10 @@ jobs: - name: Create build directory run: mkdir app/build - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - name: test-artifacts - path: app/build/outputs/apk + - name: Build QA Test Artifacts + id: build-instrumented-tests + run: | + ./gradlew --build-cache --no-daemon -PmanifestEndpoint=http://$DOCKER_IP:8420/api/ assembleQaDebug assembleQaDebugAndroidTest - name: QA Android Tests id: run-instrumented-tests @@ -269,12 +222,11 @@ jobs: name: failed-test-artifacts path: app/build/outputs/test-artifacts - - name: Teardown Heroku instance - if: always() && (steps.start-simple-server.outcome != 'success' || contains(github.ref, '/release/')) + - name: Stop Simple Docker server run: | - heroku apps:destroy \ - --app=${{ needs.deploy_server_on_heroku.outputs.heroku_app_name }} \ - --confirm=${{ needs.deploy_server_on_heroku.outputs.heroku_app_name }} + docker compose -f ".github/docker/simple-server.compose.yml" down + + mobius_migration_tests: runs-on: [ ubuntu-latest ] @@ -291,84 +243,6 @@ jobs: - name: Mobius Migration Tests run: ./gradlew :mobius-migration:test - verify_release_bundles: - runs-on: [ ubuntu-latest ] - env: - TERM: dumb - ORG_GRADLE_PROJECT_KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} - ORG_GRADLE_PROJECT_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} - ORG_GRADLE_PROJECT_KEY_ALIAS: ${{ secrets.KEY_ALIAS }} - strategy: - matrix: - buildType: [ 'Production' ] - steps: - - uses: actions/checkout@v4 - - - name: set up JDK - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: 17 - cache: 'gradle' - - - name: Decrypt secrets - run: gpg --batch --yes --quiet --decrypt --passphrase=${{ secrets.KEYSTORE_PASSPHRASE }} --output release/simple.store release/simple.gpg - - - name: Build ${{ matrix.buildType }} Release bundle - run: | - ./gradlew \ - -PrunProguard=true \ - -PdefaultProguardFile=proguard-android.txt \ - -PsentryUploadProguard=false \ - bundle${{ matrix.buildType }}Release - - - name: Clean secrets - run: | - rm -f release/simple.store - - verify_room_schemas: - runs-on: [ ubuntu-latest ] - steps: - - name: Checkout master - uses: actions/checkout@v4 - with: - ref: master - path: master - - - name: Checkout current - uses: actions/checkout@v4 - with: - path: current - - - name: Verify existing Room schemas are not modified - run: current/.github/scripts/compare_directory_contents.sh master/app/schemas/org.simple.clinic.AppDatabase current/app/schemas/org.simple.clinic.AppDatabase - - verify_pr_description: - runs-on: [ ubuntu-latest ] - if: github.event_name == 'pull_request' - steps: - - uses: actions/checkout@v4 - - name: Verify PR description - run: kotlinc -script ".github/scripts/PrCommentCheck.main.kts" "${{ github.event.pull_request.body }}" - - verify_changelog_updated: - runs-on: [ ubuntu-latest ] - if: github.event_name == 'pull_request' - steps: - - name: Checkout master - uses: actions/checkout@v4 - with: - ref: master - path: master - - - name: Checkout current - uses: actions/checkout@v4 - with: - path: current - - - name: Verify CHANGELOG was updated - run: current/.github/scripts/verify_file_was_changed.sh master/CHANGELOG.md current/CHANGELOG.md - fix_strings_ellipsise: runs-on: [ ubuntu-latest ] if: github.event_name == 'pull_request' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c71ac52a90d..e43f4abd420 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -54,10 +54,12 @@ android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:networkSecurityConfig="@xml/network_config" android:supportsRtl="true" android:theme="@style/Theme.Simple" tools:ignore="AllowBackup,DataExtractionRules,GoogleAppIndexingWarning,LockedOrientationActivity" - tools:replace="android:allowBackup"> + tools:replace="android:allowBackup" + tools:targetApi="n"> + + + + localhost + +