name: Docker Compose Cucumber tests # Reusable workflow called from build.yml when project / docker / testing # sources change. Boots the docker-compose stack and runs the cucumber # scenarios in testing/cucumber. on: workflow_call: inputs: docker-base-changed: description: "Whether the docker base image changed (forwarded from files-changed)." required: false type: string default: "false" depot_cores: description: "Depot runner vCPU count (used in runs-on). Override for benchmarking. Tuned to 4 because bench showed 16 was within noise of 4." required: false type: string default: "4" permissions: contents: read jobs: pick: uses: ./.github/workflows/_runner-pick.yml docker-compose-tests: needs: pick runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '4') }} permissions: actions: write contents: read checks: write env: DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 with: egress-policy: audit - name: Checkout Repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up JDK 25 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: java-version: "25" distribution: "temurin" - name: Cache Gradle dependency artifacts uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | ~/.gradle/wrapper ~/.gradle/caches/modules-2/files-2.1 ~/.gradle/caches/modules-2/metadata-2.* key: gradle-deps-${{ runner.os }}-jdk-25-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }} - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 with: gradle-version: 9.3.1 cache-disabled: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 # Expose ACTIONS_RUNTIME_TOKEN / ACTIONS_RESULTS_URL for docker buildx type=gha cache backend. - name: Expose GitHub runtime for Buildx cache uses: crazy-max/ghaction-github-runtime@04d248b84655b509d8c44dc1d6f990c879747487 # v4.0.0 - name: Install Docker Compose run: | sudo curl -SL "https://github.com/docker/compose/releases/download/v2.39.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" cache: "pip" # caching pip dependencies cache-dependency-path: ./testing/cucumber/requirements.txt - name: Pip requirements run: | pip install --require-hashes --only-binary=:all: -r ./testing/cucumber/requirements.txt - name: Extract JaCoCo agent for cucumber coverage # Stages build/jacoco/jacocoagent.jar where the coverage override # file bind-mounts it into the cucumber container. The agent jar # never goes into the published image - this is host-only. run: ./gradlew copyJacocoAgent -PnoSpotless - name: Run Docker Compose Tests run: | chmod +x ./testing/test_webpages.sh chmod +x ./testing/test.sh chmod +x ./testing/test_disabledEndpoints.sh ./testing/test.sh env: MAVEN_USER: ${{ secrets.MAVEN_USER }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} MAVEN_PUBLIC_URL: ${{ secrets.MAVEN_PUBLIC_URL }} DOCKER_BASE_CHANGED: ${{ inputs.docker-base-changed }} # Tells test.sh to layer testing/compose/docker-compose-coverage.override.yml # over the cucumber compose so the container starts with the # JaCoCo agent attached via JAVA_CUSTOM_OPTS. STIRLING_PDF_TEST_COVERAGE: "1" - name: Generate cucumber JaCoCo report # `if: always()` so a behave failure still produces partial # coverage from whatever endpoints did run. The exec file only # exists when the container shut down cleanly - guard so the step # is silent on the (rare) crash path. if: always() id: cucumber-coverage run: | if [ -s testing/cucumber-coverage/cucumber.exec ]; then ./gradlew jacocoReportFromExec \ -PexecFile=testing/cucumber-coverage/cucumber.exec \ -PreportDir=build/reports/jacoco/cucumber \ -PnoSpotless echo "report=true" >> "$GITHUB_OUTPUT" else echo "::warning::No cucumber .exec at testing/cucumber-coverage/cucumber.exec (container may have crashed before flushing)" echo "report=false" >> "$GITHUB_OUTPUT" fi - name: Install defusedxml for coverage summary # coverage-summary.py parses JaCoCo XML through defusedxml - # see the script header for context. if: always() && steps.cucumber-coverage.outputs.report == 'true' run: python -m pip install --quiet defusedxml - name: Cucumber coverage step summary if: always() && steps.cucumber-coverage.outputs.report == 'true' run: | python scripts/coverage-summary.py \ --title "Cucumber (docker) JaCoCo coverage" \ --jacoco "cucumber=build/reports/jacoco/cucumber/jacocoTestReport.xml" \ --github-step-summary - name: Upload cucumber JaCoCo report if: always() && steps.cucumber-coverage.outputs.report == 'true' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: jacoco-cucumber-${{ github.run_id }} path: build/reports/jacoco/cucumber/ retention-days: 7 - name: Upload raw cucumber .exec for aggregate merge # Picked up by the coverage-aggregate workflow via the # `jacoco-exec-*` artifact name pattern. if: always() && steps.cucumber-coverage.outputs.report == 'true' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: jacoco-exec-cucumber path: testing/cucumber-coverage/cucumber.exec retention-days: 7 if-no-files-found: warn - name: Upload Cucumber Report if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: cucumber-report path: testing/cucumber/report.html retention-days: 7 if-no-files-found: warn - name: Upload Test Reports if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: docker-compose-test-reports path: testing/reports/ retention-days: 7 if-no-files-found: warn - name: Cucumber Test Report if: always() uses: dorny/test-reporter@a43b3a5f7366b97d083190328d2c652e1a8b6aa2 # v3.0.0 with: name: Cucumber Tests path: testing/cucumber/junit/*.xml reporter: java-junit fail-on-error: false