diff --git a/.github/actions/setup-ci/action.yml b/.github/actions/setup-ci/action.yml new file mode 100644 index 00000000000..2855f0f26f1 --- /dev/null +++ b/.github/actions/setup-ci/action.yml @@ -0,0 +1,49 @@ +name: "Setup CI (Checkout + JDK + Gradle)" +description: "Standard CI environment setup" + +inputs: + fetch-depth: + description: "Checkout fetch depth" + required: false + default: "1" + + fetch-tags: + description: "Fetch git tags" + required: false + default: "false" + + java-version: + description: "Java version" + required: false + default: "21" + + distribution: + description: "Java distribution" + required: false + default: "zulu" + + cache-read-only: + description: "Gradle cache read-only mode" + required: false + default: "false" + +runs: + using: "composite" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: ${{ inputs.fetch-depth }} + fetch-tags: ${{ inputs.fetch-tags }} + + - name: Setup JDK + uses: actions/setup-java@v4 + with: + java-version: ${{ inputs.java-version }} + distribution: ${{ inputs.distribution }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + cache-read-only: ${{ inputs.cache-read-only }} + gradle-home-cache-cleanup: true diff --git a/.github/workflows/build-cucumber.yml b/.github/workflows/build-cucumber.yml index 197f6923841..7c94f23b91f 100644 --- a/.github/workflows/build-cucumber.yml +++ b/.github/workflows/build-cucumber.yml @@ -6,67 +6,109 @@ permissions: contents: read jobs: - verify: + build-core: + name: build-core runs-on: ubuntu-24.04 - timeout-minutes: 60 - - strategy: - fail-fast: false - matrix: - include: - - task: build-core - job_type: main - - task: cucumber - job_type: main - - task: build-progressive-loan - job_type: progressive-loan - - env: - TZ: Asia/Kolkata - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + timeout-minutes: 90 steps: - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci with: + fetch-depth: 0 + fetch-tags: true java-version: '21' distribution: 'zulu' + cache-read-only: false - - name: Cache Gradle dependencies - uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v4 + - name: Build (no tests) + run: | + ./gradlew --no-daemon --console=plain build -x test -x cucumber -x doc + + - name: Archive build reports + if: always() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 with: + name: test-results-build-core path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + **/build/reports/ + retention-days: 5 + if-no-files-found: ignore + + cucumber: + name: cucumber + needs: build-core + runs-on: ubuntu-24.04 + timeout-minutes: 120 - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + steps: + - name: Checkout + uses: actions/checkout@v4 with: - validate-wrappers: true + fetch-depth: 0 + fetch-tags: true - - name: Run Gradle Task - if: matrix.job_type == 'main' + - name: Setup CI + uses: ./.github/actions/setup-ci + with: + fetch-depth: 0 + fetch-tags: true + java-version: '21' + distribution: 'zulu' + cache-read-only: false + + - name: Run cucumber run: | - set -e # Fail the script if any command fails + ./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber - case "${{ matrix.task }}" in - build-core) - ./gradlew --no-daemon build -x test -x cucumber -x doc - ;; - cucumber) - ./gradlew --no-daemon cucumber -x :fineract-e2e-tests-runner:cucumber -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer - ;; - esac + - name: Archive test results + if: always() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 + with: + name: test-results-cucumber + path: | + **/build/reports/ + retention-days: 5 + if-no-files-found: ignore + + - name: Archive server logs + if: always() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 + with: + name: server-logs-cucumber + path: '**/build/cargo/' + retention-days: 5 + if-no-files-found: ignore + + build-progressive-loan: + name: build-progressive-loan + needs: build-core + runs-on: ubuntu-24.04 + timeout-minutes: 60 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup CI + uses: ./.github/actions/setup-ci + with: + fetch-depth: 0 + fetch-tags: true + java-version: '21' + distribution: 'zulu' + cache-read-only: false - name: Build and Test Progressive Loan - if: matrix.job_type == 'progressive-loan' run: | # Build the JAR ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar @@ -76,39 +118,31 @@ jobs: echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV echo "JAR file: $EMBEDDABLE_JAR_FILE" - # Run unit tests + # Run unit tests for the schedule generator ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:test - # Build and run sample application - mkdir -p sample-app - javac -cp "$EMBEDDABLE_JAR_FILE" -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java - java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main - java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main 25 + # Build sample app + ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:sample-app:classes + + # Run sample app (basic sanity) + java -cp "$EMBEDDABLE_JAR_FILE:fineract-progressive-loan-embeddable-schedule-generator/sample-app/build/classes/java/main" Main 25 - name: Archive test results if: always() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 with: - name: test-results-${{ matrix.task }} + name: test-results-progressive-loan path: | **/build/reports/ **/fineract-progressive-loan-embeddable-schedule-generator/build/reports/ - if-no-files-found: ignore retention-days: 5 + if-no-files-found: ignore - name: Archive Progressive Loan JAR - if: matrix.job_type == 'progressive-loan' && always() + if: always() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 with: name: progressive-loan-jar path: ${{ env.EMBEDDABLE_JAR_FILE }} retention-days: 5 if-no-files-found: ignore - - - name: Archive server logs - if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 - with: - name: server-logs-${{ matrix.task }} - path: '**/build/cargo/' - retention-days: 5 diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index c47e644511c..d3f80de3bf5 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -1,18 +1,66 @@ name: Fineract Docker Builds -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: - build: + build-image: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 60 + + outputs: + image_name: ${{ steps.meta.outputs.image_name }} + image_artifact: ${{ steps.meta.outputs.image_artifact }} + + steps: + - name: Setup CI + uses: ./.github/actions/setup-ci.yml + with: + fetch-depth: 0 + fetch-tags: true + java-version: '21' + distribution: 'zulu' + cache-read-only: false + + - name: Define image metadata + id: meta + run: | + IMAGE_NAME="fineract:local-${{ github.sha }}" + IMAGE_ARTIFACT="fineract-image-${{ github.sha }}" + echo "image_name=$IMAGE_NAME" >> "$GITHUB_OUTPUT" + echo "image_artifact=$IMAGE_ARTIFACT" >> "$GITHUB_OUTPUT" + + - name: Build Docker image (Jib) + run: | + ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image="${{ steps.meta.outputs.image_name }}" -x test -x cucumber + + - name: Save image to artifact + run: | + docker save "${{ steps.meta.outputs.image_name }}" -o fineract-image.tar + + - name: Upload image artifact + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 + with: + name: "${{ steps.meta.outputs.image_artifact }}" + path: fineract-image.tar + retention-days: 2 + + smoke: + name: Smoke (${{ matrix.db_type }}) + needs: build-image + runs-on: ubuntu-24.04 + timeout-minutes: 30 + strategy: fail-fast: false matrix: - db_type: [mariadb, postgresql] include: - db_type: mariadb compose_file: docker-compose.yml @@ -21,35 +69,77 @@ jobs: compose_file: docker-compose-postgresql.yml check_worker_health: false - env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - IMAGE_NAME: fineract - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 with: fetch-depth: 0 - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 + - name: Download image artifact + uses: actions/download-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 with: - java-version: '21' - distribution: 'zulu' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + name: "${{ needs.build-image.outputs.image_artifact }}" - - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber + - name: Load image + run: | + docker load -i fineract-image.tar + docker images | head -n 20 - name: Start the ${{ matrix.db_type }} stack - run: docker compose -f ${{ matrix.compose_file }} up -d + run: docker compose -f "${{ matrix.compose_file }}" up -d + + - name: Check containers + run: docker ps -a + + - name: Wait for Manager health + run: | + set -e + for i in $(seq 1 60); do + if curl -fsSk https://localhost:8443/fineract-provider/actuator/health >/dev/null; then + echo "Manager is healthy" + exit 0 + fi + echo "Waiting for Manager... ($i/60)" + sleep 10 + done + echo "Manager did not become healthy in time" + docker compose -f "${{ matrix.compose_file }}" ps || true + docker logs $(docker ps -q --filter name=fineract) || true + exit 1 + + - name: Optional - wait for Worker health + if: ${{ matrix.check_worker_health }} + run: | + set -e + for i in $(seq 1 60); do + if docker ps --filter "name=fineract-worker" --format "{{.Names}}: {{.Status}}" | grep -qi "healthy"; then + echo "Worker is healthy" + exit 0 + fi + echo "Waiting for Worker... ($i/60)" + sleep 10 + done + echo "Worker did not become healthy in time" + docker ps -a + exit 1 - - name: Check the stack - run: docker ps + - name: Check Manager info payload + run: | + BYTES=$(curl -fsSk https://localhost:8443/fineract-provider/actuator/info | wc --bytes) + echo "Info payload size: $BYTES bytes" + test "$BYTES" -gt 100 - - name: Check health Manager - run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + - name: Clean up stack + if: always() + run: | + docker compose -f "${{ matrix.compose_file }}" down -v + docker system prune -f - - name: Check info Manager - run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) + e2e: + name: E2E Tests + needs: build-image + uses: ./.github/workflows/build-e2e-tests.optimized.yml + with: + image_artifact: "${{ needs.build-image.outputs.image_artifact }}" + image_name: "${{ needs.build-image.outputs.image_name }}" + secrets: inherit diff --git a/.github/workflows/build-documentation.yml b/.github/workflows/build-documentation.yml index de7542fe229..281d0eef325 100644 --- a/.github/workflows/build-documentation.yml +++ b/.github/workflows/build-documentation.yml @@ -1,5 +1,10 @@ name: Fineract Documentation build -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: + permissions: contents: read jobs: diff --git a/.github/workflows/build-e2e-tests.yml b/.github/workflows/build-e2e-tests.yml index 1bbf1ac9a81..4d1bcabab58 100644 --- a/.github/workflows/build-e2e-tests.yml +++ b/.github/workflows/build-e2e-tests.yml @@ -1,180 +1,84 @@ name: Fineract E2E Tests -on: [push, pull_request] +on: + workflow_call: + inputs: + image_artifact: + required: true + type: string + image_name: + required: true + type: string + workflow_dispatch: permissions: contents: read jobs: test: - name: E2E Tests (Shard ${{ matrix.shard_index }} of ${{ matrix.total_shards }}) runs-on: ubuntu-24.04 - timeout-minutes: 60 - - strategy: - fail-fast: false - matrix: - # Define the number of shards (1-based indexing) - shard_index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - total_shards: [10] + timeout-minutes: 90 env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - IMAGE_NAME: fineract - BASE_URL: https://localhost:8443 - TEST_USERNAME: mifos - TEST_PASSWORD: password - TEST_STRONG_PASSWORD: A1b2c3d4e5f$ - TEST_TENANT_ID: default - INITIALIZATION_ENABLED: true - EVENT_VERIFICATION_ENABLED: true - ACTIVEMQ_BROKER_URL: tcp://localhost:61616 + ACTIVEMQ_USER: admin + ACTIVEMQ_PASSWORD: admin ACTIVEMQ_TOPIC_NAME: events steps: - - name: Checkout code - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: + fetch-tags: true java-version: '21' distribution: 'zulu' + cache-read-only: true - - name: Setup Gradle - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - - - name: Make scripts executable - run: chmod +x scripts/split-features.sh + - name: Download image artifact + uses: actions/download-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 + with: + name: "${{ inputs.image_artifact }}" - - name: Split feature files into shards - id: split-features + - name: Load image run: | - ./scripts/split-features.sh ${{ matrix.total_shards }} ${{ matrix.shard_index }} - echo "Shard ${{ matrix.shard_index }} feature files:" - cat feature_shard_${{ matrix.shard_index }}.txt + docker load -i fineract-image.tar + docker images | head -n 20 - - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber - - - name: Start the Fineract stack + - name: Start PostgreSQL + ActiveMQ E2E stack run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d - - name: Check the stack - run: docker ps - - - name: Wait for Manager to be ready + - name: Wait for Manager health run: | - # Wait for the container to be running - echo "Waiting for Manager container to be ready..." - timeout 300 bash -c 'until docker ps --filter "health=healthy" --filter "name=fineract" --format "{{.Status}}" | grep -q "healthy"; do - if docker ps --filter "name=fineract" --format "{{.Status}}" | grep -q "unhealthy"; then - echo "Container is unhealthy. Stopping..." - docker ps -a - docker logs $(docker ps -q --filter name=fineract) || true - exit 1 + set -e + for i in $(seq 1 60); do + if curl -fsSk https://localhost:8443/fineract-provider/actuator/health >/dev/null; then + echo "Manager is healthy" + exit 0 fi - echo "Waiting for Manager to be ready..." - sleep 5 - done' - - # Check the health endpoint - echo "Checking Manager health endpoint..." - curl -f -k --retry 30 --retry-all-errors --connect-timeout 10 --retry-delay 10 \ - https://localhost:8443/fineract-provider/actuator/health - - - name: Execute tests for shard ${{ matrix.shard_index }} - id: tests + echo "Waiting for Manager... ($i/60)" + sleep 10 + done + echo "Manager did not become healthy in time" + docker ps -a + docker logs $(docker ps -q --filter name=fineract) || true + exit 1 + + - name: Run E2E tests run: | - # Initialize failure flag - FAILED=0 - - # Create necessary directories - mkdir -p "allure-results-shard-${{ matrix.shard_index }}" - mkdir -p "allure-results-merged" - - # Read feature files from the shard file - if [ ! -s "feature_shard_${{ matrix.shard_index }}.txt" ]; then - echo "No features to test in this shard. Skipping..." - exit 0 - fi - - # Read each feature file path and run tests one by one - while IFS= read -r feature_file || [ -n "$feature_file" ]; do - # Skip empty lines - [ -z "$feature_file" ] && continue - - # Create a safe filename for the results - safe_name=$(echo "$feature_file" | tr '/' '-' | tr ' ' '_') - - echo "::group::Testing feature: $feature_file" - - # Run tests with individual allure results directory - if ! ./gradlew --no-daemon --console=plain \ - :fineract-e2e-tests-runner:cucumber \ - -Pcucumber.features="$feature_file" \ - -Dallure.results.directory="allure-results-shard-${{ matrix.shard_index }}/$safe_name" \ - allureReport; then - - echo "::error::Test failed for $feature_file" - FAILED=1 - fi - - echo "::endgroup::" - - # Copy the results to a merged directory - if [ -d "allure-results-shard-${{ matrix.shard_index }}/$safe_name" ]; then - cp -r "allure-results-shard-${{ matrix.shard_index }}/$safe_name/." "allure-results-merged/" || true - fi - done < "feature_shard_${{ matrix.shard_index }}.txt" - - # Generate individual report for this shard - if [ -d "allure-results-merged" ] && [ "$(ls -A allure-results-merged)" ]; then - echo "Generating Allure report..." - mkdir -p "allure-report-shard-${{ matrix.shard_index }}" - ./fineract-e2e-tests-runner/build/allure/commandline/bin/allure generate "allure-results-merged" --clean -o "allure-report-shard-${{ matrix.shard_index }}" || \ - echo "::warning::Failed to generate Allure report for shard ${{ matrix.shard_index }}" - fi - - # Exit with failure status if any test failed - if [ "$FAILED" -eq 1 ]; then - echo "::error::Some tests failed in this shard" - exit 1 - fi - - - name: Upload test results - if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 - with: - name: allure-results-shard-${{ matrix.shard_index }} - path: | - allure-results-shard-${{ matrix.shard_index }} - allure-results-merged - **/build/allure-results - **/build/reports/tests/test - **/build/test-results/test - retention-days: 5 - - - name: Upload Allure Report - if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 - with: - name: allure-report-shard-${{ matrix.shard_index }} - path: allure-report-shard-${{ matrix.shard_index }} - retention-days: 5 + ./gradlew --no-daemon --console=plain :fineract-e2e-tests-runner:cucumber - - name: Upload logs + - name: Archive logs & reports if: always() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4 with: - name: logs-shard-${{ matrix.shard_index }} + name: e2e-logs-and-reports path: | **/build/reports/tests/ + **/build/reports/ **/logs/ **/out/ retention-days: 5 + if-no-files-found: ignore - name: Clean up if: always() diff --git a/.github/workflows/build-mariadb.yml b/.github/workflows/build-mariadb.yml index 5f890b8b8e3..5ea86252f73 100644 --- a/.github/workflows/build-mariadb.yml +++ b/.github/workflows/build-mariadb.yml @@ -1,12 +1,17 @@ name: Fineract Cargo & Unit- & Integration tests - MariaDB -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: test: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -43,30 +48,14 @@ jobs: FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 fetch-tags: true - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: java-version: '21' distribution: 'zulu' - - - name: Cache Gradle dependencies - uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - with: - validate-wrappers: true + cache-read-only: true - name: Verify MariaDB connection run: | diff --git a/.github/workflows/build-mysql.yml b/.github/workflows/build-mysql.yml index bcd886c8670..7424ea92d0d 100644 --- a/.github/workflows/build-mysql.yml +++ b/.github/workflows/build-mysql.yml @@ -1,12 +1,17 @@ name: Fineract Cargo & Unit- & Integration tests - MySQL -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: test: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -43,30 +48,14 @@ jobs: FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 fetch-tags: true - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: java-version: '21' distribution: 'zulu' - - - name: Cache Gradle dependencies - uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - with: - validate-wrappers: true + cache-read-only: true - name: Verify MySQL connection run: | diff --git a/.github/workflows/build-postgresql.yml b/.github/workflows/build-postgresql.yml index 1f0213997e9..a4ba7bbc8fe 100644 --- a/.github/workflows/build-postgresql.yml +++ b/.github/workflows/build-postgresql.yml @@ -1,12 +1,17 @@ name: Fineract Cargo & Unit- & Integration tests - PostgreSQL -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: test: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -44,30 +49,14 @@ jobs: FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 fetch-tags: true - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: java-version: '21' distribution: 'zulu' - - - name: Cache Gradle dependencies - uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - with: - validate-wrappers: true + cache-read-only: true - name: Verify PostgreSQL connection run: | diff --git a/.github/workflows/liquibase-only-postgresql.yml b/.github/workflows/liquibase-only-postgresql.yml index 06e72ef7c53..9ab0d6cb40e 100644 --- a/.github/workflows/liquibase-only-postgresql.yml +++ b/.github/workflows/liquibase-only-postgresql.yml @@ -1,12 +1,17 @@ name: Fineract Liquibase Only mode - PostgreSQL -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: test: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-22.04 timeout-minutes: 60 @@ -25,30 +30,14 @@ jobs: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 fetch-tags: true - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: java-version: '21' distribution: 'zulu' - - - name: Cache Gradle dependencies - uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - with: - validate-wrappers: true + cache-read-only: true - name: Verify PostgreSQL connection run: | diff --git a/.github/workflows/publish-dockerhub.yml b/.github/workflows/publish-dockerhub.yml index e0e94f11c20..73fc30ce882 100644 --- a/.github/workflows/publish-dockerhub.yml +++ b/.github/workflows/publish-dockerhub.yml @@ -9,6 +9,7 @@ permissions: contents: read jobs: build: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 60 env: diff --git a/.github/workflows/run-integration-test-sequentially-postgresql.yml b/.github/workflows/run-integration-test-sequentially-postgresql.yml index 2ac25237be9..6e180c46c30 100644 --- a/.github/workflows/run-integration-test-sequentially-postgresql.yml +++ b/.github/workflows/run-integration-test-sequentially-postgresql.yml @@ -9,6 +9,7 @@ permissions: contents: read jobs: build: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-24.04 timeout-minutes: 180 @@ -32,21 +33,15 @@ jobs: TZ: Asia/Kolkata DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + - name: Setup CI + uses: ./.github/actions/setup-ci.yml with: fetch-depth: 0 fetch-tags: true - - - name: Set up JDK 21 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5 - with: java-version: '21' distribution: 'zulu' - - name: Setup Gradle and Validate Wrapper - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - with: - validate-wrappers: true + cache-read-only: true + - name: Verify PostgreSQL connection run: | while ! pg_isready -d postgres -U root -h 127.0.0.1 -p 5432 ; do diff --git a/.github/workflows/smoke-messaging.yml b/.github/workflows/smoke-messaging.yml index 01b7e18f628..7875b52f606 100644 --- a/.github/workflows/smoke-messaging.yml +++ b/.github/workflows/smoke-messaging.yml @@ -1,12 +1,17 @@ name: Fineract Messaging Smoke Tests -on: [push, pull_request] +on: + workflow_run: + workflows: ["Fineract Build & Cucumber tests (without E2E tests)"] + types: [completed] + workflow_dispatch: permissions: contents: read jobs: smoke-test: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} name: Smoke Test with ${{ matrix.messaging }} runs-on: ubuntu-24.04 timeout-minutes: 60 diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature index 48856d17c3d..6aa83c28537 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature @@ -121,7 +121,7 @@ Feature: LoanCharge When Admin sets the business date to "23 October 2022" And Admin adds an NSF fee because of payment bounce with "23 October 2022" transaction date Then Loan has 1010 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -149,7 +149,7 @@ Feature: LoanCharge When Admin sets the business date to "04 November 2022" When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with 3 EUR transaction amount and externalId "" Then Loan has 1007 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -181,7 +181,7 @@ Feature: LoanCharge # --- Backdated repayment with 8 EUR --- And Customer makes "AUTOPAY" repayment on "25 October 2022" with 8 EUR transaction amount Then Loan has 999 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -221,7 +221,7 @@ Feature: LoanCharge # --- revert last charge adjustment (was amount 3) --- When Admin reverts the charge adjustment which was raised on "04 November 2022" with 3 EUR transaction amount Then Loan has 1002 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -262,7 +262,7 @@ Feature: LoanCharge # --- Add snooze fee on 10/27/2022 with amount 9 --- And Admin adds "LOAN_SNOOZE_FEE" due date charge with "27 October 2022" due date and 9 EUR transaction amount Then Loan has 1011 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -309,7 +309,7 @@ Feature: LoanCharge # --- charge adjustment for snooze fee with 4 --- When Admin makes a charge adjustment for the last "LOAN_SNOOZE_FEE" type charge which is due on "27 October 2022" with 4 EUR transaction amount and externalId "" Then Loan has 1007 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -359,7 +359,7 @@ Feature: LoanCharge # --- Backdated repayment with 507 EUR --- And Customer makes "AUTOPAY" repayment on "31 October 2022" with 507 EUR transaction amount Then Loan has 500 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -415,7 +415,7 @@ Feature: LoanCharge # --- charge adjustment for nsf fee with 5 --- When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with 5 EUR transaction amount and externalId "" Then Loan has 495 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -474,7 +474,7 @@ Feature: LoanCharge # --- Backdated repayment with 494 EUR --- And Customer makes "AUTOPAY" repayment on "1 November 2022" with 494 EUR transaction amount Then Loan has 1 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -539,7 +539,7 @@ Feature: LoanCharge When Admin makes a charge adjustment for the last "LOAN_SNOOZE_FEE" type charge which is due on "27 October 2022" with 1 EUR transaction amount and externalId "" Then Loan status will be "CLOSED_OBLIGATIONS_MET" Then Loan has 0 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -607,7 +607,7 @@ Feature: LoanCharge When Admin reverts the charge adjustment which was raised on "04 November 2022" with 1 EUR transaction amount Then Loan status will be "ACTIVE" Then Loan has 1 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -677,7 +677,7 @@ Feature: LoanCharge When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with 1 EUR transaction amount and externalId "" Then Loan status will be "CLOSED_OBLIGATIONS_MET" Then Loan has 0 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -750,7 +750,7 @@ Feature: LoanCharge When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with 2 EUR transaction amount and externalId "" Then Loan status will be "OVERPAID" Then Loan has 0 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -826,7 +826,7 @@ Feature: LoanCharge When Admin reverts the charge adjustment which was raised on "04 November 2022" with 2 EUR transaction amount Then Loan status will be "CLOSED_OBLIGATIONS_MET" Then Loan has 0 outstanding amount - And Admin runs the Add Periodic Accrual Transactions job + When Admin runs inline COB job for Loan Then Loan Repayment schedule has 2 periods, with the following data for periods: | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | | | 22 October 2022 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -5188,11 +5188,7 @@ Feature: LoanCharge | INCOME | 404007 | Fee Income | | 1.0 | | LIABILITY | 145023 | Suspense/Clearing account | 1.0 | | # Run income recognition for accrual test - And Admin runs the Accrual Activity Posting job - And Admin runs the Add Accrual Transactions job - And Admin runs the Add Accrual Transactions For Loans With Income Posted As Transactions job - And Admin runs the Add Periodic Accrual Transactions job - And Admin runs the Recalculate Interest for Loans job + When Admin runs inline COB job for Loan Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | @@ -5319,11 +5315,7 @@ Feature: LoanCharge | LIABILITY | 145023 | Suspense/Clearing account | 5.0 | | # Run income recognition for accrual test When Admin sets the business date to "03 March 2024" - And Admin runs the Accrual Activity Posting job - And Admin runs the Add Accrual Transactions job - And Admin runs the Add Accrual Transactions For Loans With Income Posted As Transactions job - And Admin runs the Add Periodic Accrual Transactions job - And Admin runs the Recalculate Interest for Loans job + When Admin runs inline COB job for Loan Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | @@ -5467,11 +5459,7 @@ Feature: LoanCharge | LIABILITY | 145023 | Suspense/Clearing account | 5.0 | | # Run income recognition for accrual test When Admin sets the business date to "03 March 2024" - And Admin runs the Accrual Activity Posting job - And Admin runs the Add Accrual Transactions job - And Admin runs the Add Accrual Transactions For Loans With Income Posted As Transactions job - And Admin runs the Add Periodic Accrual Transactions job - And Admin runs the Recalculate Interest for Loans job + When Admin runs inline COB job for Loan Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |