From 4327b1a235d102319c973d9ab2f5e62655b341c5 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Mon, 20 Apr 2026 18:07:33 -0600 Subject: [PATCH 01/19] try coverage tests on self-hosted runners and coveralls --- .../workflows/self_hosted_build_and_test.yml | 115 ++++++++++++++++-- 1 file changed, 105 insertions(+), 10 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 23830d94ffd..a5c0803431c 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -1,7 +1,7 @@ name: Self-Hosted Build and Test on: - push: + pull_request: branches: [ develop ] workflow_dispatch: inputs: @@ -10,32 +10,127 @@ on: required: false default: "" +env: + PYTHON_REQUIRED_VERSION: "3.12.2" + FC: gfortran-13 + jobs: - build_and_test: - name: Build and Test (Ubuntu matrix) + coverage: + name: Coverage (${{ matrix.coverage.name }}) strategy: fail-fast: false matrix: runner: - [self-hosted, linux, x64, ubuntu-24.04] + coverage: + - name: "Unit Tests" + build_dir: build-unit-coverage + ctest_selection_flag: -E + ctest_selection_pattern: "integration.*" + coveralls_flag: unit-tests + artifact_name: unit_test_coverage_results + - name: "Integration Tests" + build_dir: build-integration-coverage + ctest_selection_flag: -R + ctest_selection_pattern: "integration.*" + coveralls_flag: integration-tests + artifact_name: integration_test_coverage_results runs-on: ${{ matrix.runner }} steps: + - name: Set up Python ${{ env.PYTHON_REQUIRED_VERSION }} + id: setup-python + uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_REQUIRED_VERSION }} + + - name: Install Linux coverage dependencies + run: | + sudo apt-get update + sudo apt-get install -y libxkbcommon-x11-0 xorg-dev libgl1-mesa-dev lcov gcovr + echo "FC=gfortran-13" >> "$GITHUB_ENV" + - name: Checkout EnergyPlus uses: actions/checkout@v6 with: ref: ${{ github.event.inputs.ref || github.ref }} - - name: Configure + - name: Configure ${{ matrix.coverage.name }} run: > - cmake -S . -B build + cmake -S . -B ${{ matrix.coverage.build_dir }} -G "Unix Makefiles" - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=RelWithDebInfo + -DLINK_WITH_PYTHON:BOOL=ON + -DPYTHON_CLI:BOOL=OFF + -DPython_REQUIRED_VERSION:STRING=${{ steps.setup-python.outputs.python-version }} + -DPython_ROOT_DIR:PATH=$RUNNER_TOOL_CACHE/Python/${{ steps.setup-python.outputs.python-version }}/x64/ + -DBUILD_FORTRAN:BOOL=ON -DBUILD_TESTING=ON -DBUILD_PACKAGE=OFF -DDOCUMENTATION_BUILD=DoNotBuild + -DENABLE_REGRESSION_TESTING:BOOL=OFF + -DENABLE_COVERAGE:BOOL=ON + -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF + -DENABLE_PCH:BOOL=OFF + -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON + -DCOMMIT_SHA:STRING=$(git rev-parse HEAD) + + - name: Build ${{ matrix.coverage.name }} + run: cmake --build ${{ matrix.coverage.build_dir }} -j "$(nproc)" + + - name: Run ${{ matrix.coverage.name }} + run: > + ctest + --test-dir ${{ matrix.coverage.build_dir }} + ${{ matrix.coverage.ctest_selection_flag }} "${{ matrix.coverage.ctest_selection_pattern }}" + --output-on-failure + -j "$(nproc)" + + - name: Generate raw ${{ matrix.coverage.name }} coverage results + working-directory: ${{ matrix.coverage.build_dir }} + run: lcov -c -d . -o ./lcov.output --no-external --base-directory ../src/EnergyPlus/ + + - name: Generate filtered ${{ matrix.coverage.name }} coverage results + working-directory: ${{ matrix.coverage.build_dir }} + run: lcov -r ./lcov.output "${{ github.workspace }}/${{ matrix.coverage.build_dir }}/*" -o lcov.output.filtered - - name: Build - run: cmake --build build -j "$(nproc)" + - name: Generate HTML ${{ matrix.coverage.name }} coverage results + working-directory: ${{ matrix.coverage.build_dir }} + run: genhtml ./lcov.output.filtered -o lcov-html --demangle-cpp --function-coverage | tee cover.txt - - name: Run tests - run: ctest --test-dir build -j "$(nproc)" + - name: Process ${{ matrix.coverage.name }} coverage summary + working-directory: ${{ matrix.coverage.build_dir }} + run: python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + + - name: Add ${{ matrix.coverage.name }} coverage summary to job summary + run: echo "$(cat ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/cover.md)" >> "$GITHUB_STEP_SUMMARY" + + - name: Upload ${{ matrix.coverage.name }} coverage to Coveralls + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov.output.filtered + format: lcov + flag-name: ${{ matrix.coverage.coveralls_flag }} + parallel: true + build-number: ${{ github.run_id }} + + - name: Upload ${{ matrix.coverage.name }} coverage artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.coverage.artifact_name }} + path: | + ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov.output.filtered + ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov-html + + coveralls_finish: + name: Finish Coveralls Coverage Build + needs: coverage + if: ${{ always() }} + runs-on: [self-hosted, linux, x64, ubuntu-24.04] + steps: + - name: Close Coveralls parallel build + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true + build-number: ${{ github.run_id }} From bc055c3604763d890bbca8dae1f560509f4a97bb Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 11:18:26 -0600 Subject: [PATCH 02/19] combine unit and integration tests, try using ccache, exclude some of the longest running files --- .../workflows/self_hosted_build_and_test.yml | 210 ++++++++++++------ 1 file changed, 139 insertions(+), 71 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index a5c0803431c..611513264f9 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -13,56 +13,60 @@ on: env: PYTHON_REQUIRED_VERSION: "3.12.2" FC: gfortran-13 + BUILD_DIR: build-coverage + INTEGRATION_EXCLUDE_REGEX: >- + ^integration\.(UnitaryHybridAC_DedicatedOutsideAir|HospitalLowEnergy|GSHP-GLHE-CalcGFunctions|HospitalBaselineReheatReportEMS|HospitalBaseline|RefBldgOutPatientNew2004_Chicago|ASHRAE901_ApartmentHighRise_STD2019_Denver|UnitarySystem_VariableSpeedDX_SZVAV|ASHRAE901_OutPatientHealthCare_STD2019_Denver|UnitarySystem_MultiSpeedDX_EconoStaging|RefBldgSecondarySchoolNew2004_Chicago|RefrigeratedWarehouse|HeatPumpWaterHeaterStratified|ASHRAE901_OfficeLarge_STD2019_Denver_Chiller205|ASHRAE901_OfficeLarge_STD2019_Denver_Chiller205_Detailed|_5ZoneAirCooled_LeapYear_annual|_5ZoneAirCooled_annual|_SmallOffice_Dulles|EcoroofOrlando|EcoroofOrlando_NoSitePrec)$ jobs: coverage: - name: Coverage (${{ matrix.coverage.name }}) - strategy: - fail-fast: false - matrix: - runner: - - [self-hosted, linux, x64, ubuntu-24.04] - coverage: - - name: "Unit Tests" - build_dir: build-unit-coverage - ctest_selection_flag: -E - ctest_selection_pattern: "integration.*" - coveralls_flag: unit-tests - artifact_name: unit_test_coverage_results - - name: "Integration Tests" - build_dir: build-integration-coverage - ctest_selection_flag: -R - ctest_selection_pattern: "integration.*" - coveralls_flag: integration-tests - artifact_name: integration_test_coverage_results - runs-on: ${{ matrix.runner }} + name: Coverage + runs-on: [self-hosted, linux, x64, ubuntu-24.04] steps: - - name: Set up Python ${{ env.PYTHON_REQUIRED_VERSION }} - id: setup-python - uses: actions/setup-python@v6 + - name: Checkout EnergyPlus + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + + - name: Setup runner + id: setup-runner + uses: ./.github/actions/setup-runner with: python-version: ${{ env.PYTHON_REQUIRED_VERSION }} + python-arch: x64 - - name: Install Linux coverage dependencies + - name: Restore ccache + uses: actions/cache/restore@v5 + id: cacheccache-restore + with: + path: | + ${{ steps.setup-runner.outputs.ccache-dir }} + key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ github.event.pull_request.head.ref || github.event.inputs.ref || github.ref_name }}-coverage + restore-keys: | + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ github.event.pull_request.head.ref || github.event.inputs.ref || github.ref_name }} + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}- + ccache-self-hosted-linux- + + - name: Install Linux coverage tools run: | - sudo apt-get update - sudo apt-get install -y libxkbcommon-x11-0 xorg-dev libgl1-mesa-dev lcov gcovr - echo "FC=gfortran-13" >> "$GITHUB_ENV" + sudo apt-get -qq update + sudo apt-get -qq install -y lcov gcovr - - name: Checkout EnergyPlus - uses: actions/checkout@v6 - with: - ref: ${{ github.event.inputs.ref || github.ref }} + - name: Show restored ccache stats + shell: bash + run: | + ccache --show-stats -vv || ccache --show-stats + ccache --zero-stats + ccache -p - - name: Configure ${{ matrix.coverage.name }} + - name: Configure coverage build run: > - cmake -S . -B ${{ matrix.coverage.build_dir }} + cmake -S . -B ${{ env.BUILD_DIR }} -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLINK_WITH_PYTHON:BOOL=ON -DPYTHON_CLI:BOOL=OFF - -DPython_REQUIRED_VERSION:STRING=${{ steps.setup-python.outputs.python-version }} - -DPython_ROOT_DIR:PATH=$RUNNER_TOOL_CACHE/Python/${{ steps.setup-python.outputs.python-version }}/x64/ + -DPython_REQUIRED_VERSION:STRING=${{ env.PYTHON_REQUIRED_VERSION }} + -DPython_ROOT_DIR:PATH=${{ steps.setup-runner.outputs.python-root-dir }} -DBUILD_FORTRAN:BOOL=ON -DBUILD_TESTING=ON -DBUILD_PACKAGE=OFF @@ -72,65 +76,129 @@ jobs: -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF -DENABLE_PCH:BOOL=OFF -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON - -DCOMMIT_SHA:STRING=$(git rev-parse HEAD) + -DCOMMIT_SHA:STRING="$(git rev-parse HEAD)" + + - name: Build coverage targets + run: cmake --build ${{ env.BUILD_DIR }} -j "${{ steps.setup-runner.outputs.nproc }}" + + - name: Show post-build ccache stats + shell: bash + run: ccache --show-stats -vv || ccache --show-stats + + - name: Run unit tests + run: > + ctest + --test-dir ${{ env.BUILD_DIR }} + -E "integration.*" + --output-on-failure + -j "${{ steps.setup-runner.outputs.nproc }}" + + - name: Create coverage output directories + working-directory: ${{ env.BUILD_DIR }} + run: mkdir -p coverage/unit coverage/integration + + - name: Generate raw unit test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ + + - name: Generate filtered unit test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: lcov -r coverage/unit/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/unit/lcov.output.filtered + + - name: Generate HTML unit test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage | tee coverage/unit/cover.txt - - name: Build ${{ matrix.coverage.name }} - run: cmake --build ${{ matrix.coverage.build_dir }} -j "$(nproc)" + - name: Process unit test coverage summary + working-directory: ${{ env.BUILD_DIR }}/coverage/unit + run: python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + + - name: Add unit test coverage summary to job summary + run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/cover.md >> "$GITHUB_STEP_SUMMARY" + + - name: Clear coverage counters before integration tests + run: python ${{ github.workspace }}/scripts/dev/clear_coverage_results.py ${{ env.BUILD_DIR }} - - name: Run ${{ matrix.coverage.name }} + - name: Run integration tests excluding top 20 slowest tests run: > ctest - --test-dir ${{ matrix.coverage.build_dir }} - ${{ matrix.coverage.ctest_selection_flag }} "${{ matrix.coverage.ctest_selection_pattern }}" + --test-dir ${{ env.BUILD_DIR }} + -R "integration.*" + -E "${{ env.INTEGRATION_EXCLUDE_REGEX }}" --output-on-failure - -j "$(nproc)" + -j "${{ steps.setup-runner.outputs.nproc }}" - - name: Generate raw ${{ matrix.coverage.name }} coverage results - working-directory: ${{ matrix.coverage.build_dir }} - run: lcov -c -d . -o ./lcov.output --no-external --base-directory ../src/EnergyPlus/ + - name: Generate raw integration test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ - - name: Generate filtered ${{ matrix.coverage.name }} coverage results - working-directory: ${{ matrix.coverage.build_dir }} - run: lcov -r ./lcov.output "${{ github.workspace }}/${{ matrix.coverage.build_dir }}/*" -o lcov.output.filtered + - name: Generate filtered integration test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: lcov -r coverage/integration/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/integration/lcov.output.filtered - - name: Generate HTML ${{ matrix.coverage.name }} coverage results - working-directory: ${{ matrix.coverage.build_dir }} - run: genhtml ./lcov.output.filtered -o lcov-html --demangle-cpp --function-coverage | tee cover.txt + - name: Generate HTML integration test coverage results + working-directory: ${{ env.BUILD_DIR }} + run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage | tee coverage/integration/cover.txt - - name: Process ${{ matrix.coverage.name }} coverage summary - working-directory: ${{ matrix.coverage.build_dir }} + - name: Process integration test coverage summary + working-directory: ${{ env.BUILD_DIR }}/coverage/integration run: python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py - - name: Add ${{ matrix.coverage.name }} coverage summary to job summary - run: echo "$(cat ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/cover.md)" >> "$GITHUB_STEP_SUMMARY" + - name: Add integration test coverage summary to job summary + run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/cover.md >> "$GITHUB_STEP_SUMMARY" - - name: Upload ${{ matrix.coverage.name }} coverage to Coveralls + - name: Upload unit test coverage to Coveralls + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov.output.filtered + file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.filtered format: lcov - flag-name: ${{ matrix.coverage.coveralls_flag }} + flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} - - name: Upload ${{ matrix.coverage.name }} coverage artifacts - uses: actions/upload-artifact@v4 + - name: Upload integration test coverage to Coveralls + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + uses: coverallsapp/github-action@v2 with: - name: ${{ matrix.coverage.artifact_name }} - path: | - ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov.output.filtered - ${{ github.workspace }}/${{ matrix.coverage.build_dir }}/lcov-html + github-token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.filtered + format: lcov + flag-name: integration-tests + parallel: true + build-number: ${{ github.run_id }} - coveralls_finish: - name: Finish Coveralls Coverage Build - needs: coverage - if: ${{ always() }} - runs-on: [self-hosted, linux, x64, ubuntu-24.04] - steps: - - name: Close Coveralls parallel build + - name: Finish Coveralls coverage build + if: always() uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true build-number: ${{ github.run_id }} + + - name: Upload unit test coverage artifacts + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + uses: actions/upload-artifact@v4 + with: + name: unit_test_coverage_results + path: | + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.filtered + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov-html + + - name: Upload integration test coverage artifacts + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + uses: actions/upload-artifact@v4 + with: + name: integration_test_coverage_results + path: | + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.filtered + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov-html + + - name: Save ccache + if: always() && steps.cacheccache-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v5 + with: + path: | + ${{ steps.setup-runner.outputs.ccache-dir }} + key: ${{ steps.cacheccache-restore.outputs.cache-primary-key }} From da56f7aa88a5defbb4cb1c2e2e4e97defe4f16f9 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 11:59:26 -0600 Subject: [PATCH 03/19] use branch SHA in caching keys, run design day-only simulations, patch failing coverage on generated files --- .../workflows/self_hosted_build_and_test.yml | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 611513264f9..1bfc73c47c1 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -14,6 +14,8 @@ env: PYTHON_REQUIRED_VERSION: "3.12.2" FC: gfortran-13 BUILD_DIR: build-coverage + ANNUAL_SIMULATION_EXCLUDE_REGEX: >- + ^integration\.(GSHP-GLHE-BoreholeFieldDesign|PythonPluginSolarHeating|_5ZoneAirCooled_annual|_5ZoneAirCooled_LeapYear_annual|UnitarySystem_MultiSpeedDX_EconoStaging|UnitarySystem_VariableSpeedDX_SZVAV|_ResidentialBase|_ExternalInterface-functionalmockupunit-to-actuator|_ExternalInterface-functionalmockupunit-to-schedule|_ExternalInterface-functionalmockupunit-to-variable)$ INTEGRATION_EXCLUDE_REGEX: >- ^integration\.(UnitaryHybridAC_DedicatedOutsideAir|HospitalLowEnergy|GSHP-GLHE-CalcGFunctions|HospitalBaselineReheatReportEMS|HospitalBaseline|RefBldgOutPatientNew2004_Chicago|ASHRAE901_ApartmentHighRise_STD2019_Denver|UnitarySystem_VariableSpeedDX_SZVAV|ASHRAE901_OutPatientHealthCare_STD2019_Denver|UnitarySystem_MultiSpeedDX_EconoStaging|RefBldgSecondarySchoolNew2004_Chicago|RefrigeratedWarehouse|HeatPumpWaterHeaterStratified|ASHRAE901_OfficeLarge_STD2019_Denver_Chiller205|ASHRAE901_OfficeLarge_STD2019_Denver_Chiller205_Detailed|_5ZoneAirCooled_LeapYear_annual|_5ZoneAirCooled_annual|_SmallOffice_Dulles|EcoroofOrlando|EcoroofOrlando_NoSitePrec)$ @@ -27,6 +29,11 @@ jobs: with: ref: ${{ github.event.inputs.ref || github.ref }} + - name: Resolve checked out SHA + id: checkout-sha + shell: bash + run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + - name: Setup runner id: setup-runner uses: ./.github/actions/setup-runner @@ -40,9 +47,8 @@ jobs: with: path: | ${{ steps.setup-runner.outputs.ccache-dir }} - key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ github.event.pull_request.head.ref || github.event.inputs.ref || github.ref_name }}-coverage + key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ steps.checkout-sha.outputs.sha }}-coverage restore-keys: | - ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ github.event.pull_request.head.ref || github.event.inputs.ref || github.ref_name }} ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}- ccache-self-hosted-linux- @@ -72,6 +78,7 @@ jobs: -DBUILD_PACKAGE=OFF -DDOCUMENTATION_BUILD=DoNotBuild -DENABLE_REGRESSION_TESTING:BOOL=OFF + -DTEST_ANNUAL_SIMULATION:BOOL=OFF -DENABLE_COVERAGE:BOOL=ON -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF -DENABLE_PCH:BOOL=OFF @@ -99,11 +106,13 @@ jobs: - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ + run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source - name: Generate filtered unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -r coverage/unit/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/unit/lcov.output.filtered + run: | + lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.srconly + lcov -r coverage/unit/lcov.output.srconly "*/ConfiguredFunctions.cc" "*/DataStringGlobals.cc" -o coverage/unit/lcov.output.filtered - name: Generate HTML unit test coverage results working-directory: ${{ env.BUILD_DIR }} @@ -119,22 +128,24 @@ jobs: - name: Clear coverage counters before integration tests run: python ${{ github.workspace }}/scripts/dev/clear_coverage_results.py ${{ env.BUILD_DIR }} - - name: Run integration tests excluding top 20 slowest tests + - name: Run integration tests excluding slowest and annual-only tests run: > ctest --test-dir ${{ env.BUILD_DIR }} -R "integration.*" - -E "${{ env.INTEGRATION_EXCLUDE_REGEX }}" + -E "${{ env.INTEGRATION_EXCLUDE_REGEX }}|${{ env.ANNUAL_SIMULATION_EXCLUDE_REGEX }}" --output-on-failure -j "${{ steps.setup-runner.outputs.nproc }}" - name: Generate raw integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ + run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source - name: Generate filtered integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -r coverage/integration/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/integration/lcov.output.filtered + run: | + lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.srconly + lcov -r coverage/integration/lcov.output.srconly "*/ConfiguredFunctions.cc" "*/DataStringGlobals.cc" -o coverage/integration/lcov.output.filtered - name: Generate HTML integration test coverage results working-directory: ${{ env.BUILD_DIR }} From e9e637bca53454f1d7afd0c5304b3d0ff7136738 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 12:34:28 -0600 Subject: [PATCH 04/19] another try with generated files, only run on energyplus project --- .github/workflows/self_hosted_build_and_test.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 1bfc73c47c1..759ed9ce7eb 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -104,9 +104,16 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: mkdir -p coverage/unit coverage/integration + - name: Stage generated EnergyPlus sources for coverage + run: | + install -d "${{ github.workspace }}/src/EnergyPlus/embedded" + cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/src/EnergyPlus/ConfiguredFunctions.cc" "${{ github.workspace }}/src/EnergyPlus/ConfiguredFunctions.cc" + cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/src/EnergyPlus/DataStringGlobals.cc" "${{ github.workspace }}/src/EnergyPlus/DataStringGlobals.cc" + cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/idd/embedded/EmbeddedEpJSONSchema.cc" "${{ github.workspace }}/src/EnergyPlus/embedded/EmbeddedEpJSONSchema.cc" + - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source + run: lcov -c -d ./src/EnergyPlus -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source - name: Generate filtered unit test coverage results working-directory: ${{ env.BUILD_DIR }} @@ -139,7 +146,7 @@ jobs: - name: Generate raw integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source + run: lcov -c -d ./src/EnergyPlus -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source - name: Generate filtered integration test coverage results working-directory: ${{ env.BUILD_DIR }} From 043a47cc36f33ba77a2b3990ca2bc5a86b7db974 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 14:03:55 -0600 Subject: [PATCH 05/19] more issues with generated files --- .../workflows/self_hosted_build_and_test.yml | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 759ed9ce7eb..d8348f9cbc7 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -105,11 +105,27 @@ jobs: run: mkdir -p coverage/unit coverage/integration - name: Stage generated EnergyPlus sources for coverage + working-directory: ${{ env.BUILD_DIR }} run: | install -d "${{ github.workspace }}/src/EnergyPlus/embedded" - cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/src/EnergyPlus/ConfiguredFunctions.cc" "${{ github.workspace }}/src/EnergyPlus/ConfiguredFunctions.cc" - cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/src/EnergyPlus/DataStringGlobals.cc" "${{ github.workspace }}/src/EnergyPlus/DataStringGlobals.cc" - cp -f "${{ github.workspace }}/${{ env.BUILD_DIR }}/idd/embedded/EmbeddedEpJSONSchema.cc" "${{ github.workspace }}/src/EnergyPlus/embedded/EmbeddedEpJSONSchema.cc" + : > coverage/generated-source-patterns.txt + for generated in src/EnergyPlus/*.cc; do + [[ -e "${generated}" ]] || continue + target="${{ github.workspace }}/src/EnergyPlus/$(basename "${generated}")" + if [[ ! -e "${target}" ]]; then + cp -f "${generated}" "${target}" + echo "*/$(basename "${generated}")" >> coverage/generated-source-patterns.txt + fi + done + for generated in idd/embedded/*.cc; do + [[ -e "${generated}" ]] || continue + target="${{ github.workspace }}/src/EnergyPlus/embedded/$(basename "${generated}")" + if [[ ! -e "${target}" ]]; then + cp -f "${generated}" "${target}" + echo "*/embedded/$(basename "${generated}")" >> coverage/generated-source-patterns.txt + fi + done + sort -u -o coverage/generated-source-patterns.txt coverage/generated-source-patterns.txt - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} @@ -119,7 +135,12 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: | lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.srconly - lcov -r coverage/unit/lcov.output.srconly "*/ConfiguredFunctions.cc" "*/DataStringGlobals.cc" -o coverage/unit/lcov.output.filtered + if [[ -s coverage/generated-source-patterns.txt ]]; then + mapfile -t generated_patterns < coverage/generated-source-patterns.txt + lcov -r coverage/unit/lcov.output.srconly "${generated_patterns[@]}" -o coverage/unit/lcov.output.filtered + else + cp -f coverage/unit/lcov.output.srconly coverage/unit/lcov.output.filtered + fi - name: Generate HTML unit test coverage results working-directory: ${{ env.BUILD_DIR }} @@ -152,7 +173,12 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: | lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.srconly - lcov -r coverage/integration/lcov.output.srconly "*/ConfiguredFunctions.cc" "*/DataStringGlobals.cc" -o coverage/integration/lcov.output.filtered + if [[ -s coverage/generated-source-patterns.txt ]]; then + mapfile -t generated_patterns < coverage/generated-source-patterns.txt + lcov -r coverage/integration/lcov.output.srconly "${generated_patterns[@]}" -o coverage/integration/lcov.output.filtered + else + cp -f coverage/integration/lcov.output.srconly coverage/integration/lcov.output.filtered + fi - name: Generate HTML integration test coverage results working-directory: ${{ env.BUILD_DIR }} From 822e1e190a24d9ce841f8e693ecad6924a30ff64 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 19:25:23 -0600 Subject: [PATCH 06/19] one more try --- .../workflows/self_hosted_build_and_test.yml | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index d8348f9cbc7..68e8fa258a5 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -107,25 +107,13 @@ jobs: - name: Stage generated EnergyPlus sources for coverage working-directory: ${{ env.BUILD_DIR }} run: | - install -d "${{ github.workspace }}/src/EnergyPlus/embedded" - : > coverage/generated-source-patterns.txt for generated in src/EnergyPlus/*.cc; do [[ -e "${generated}" ]] || continue target="${{ github.workspace }}/src/EnergyPlus/$(basename "${generated}")" if [[ ! -e "${target}" ]]; then cp -f "${generated}" "${target}" - echo "*/$(basename "${generated}")" >> coverage/generated-source-patterns.txt fi done - for generated in idd/embedded/*.cc; do - [[ -e "${generated}" ]] || continue - target="${{ github.workspace }}/src/EnergyPlus/embedded/$(basename "${generated}")" - if [[ ! -e "${target}" ]]; then - cp -f "${generated}" "${target}" - echo "*/embedded/$(basename "${generated}")" >> coverage/generated-source-patterns.txt - fi - done - sort -u -o coverage/generated-source-patterns.txt coverage/generated-source-patterns.txt - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} @@ -135,9 +123,15 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: | lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.srconly - if [[ -s coverage/generated-source-patterns.txt ]]; then - mapfile -t generated_patterns < coverage/generated-source-patterns.txt - lcov -r coverage/unit/lcov.output.srconly "${generated_patterns[@]}" -o coverage/unit/lcov.output.filtered + awk -F: '/^SF:/{print $2}' coverage/unit/lcov.output.srconly | while read -r source_file; do + rel_path="${source_file#${{ github.workspace }}/}" + if [[ "${source_file}" == "${{ github.workspace }}/src/EnergyPlus/"* ]] && ! git -C "${{ github.workspace }}" ls-files --error-unmatch -- "${rel_path}" >/dev/null 2>&1; then + printf '%s\n' "${source_file}" + fi + done | sort -u > coverage/unit/excluded-generated-files.txt + if [[ -s coverage/unit/excluded-generated-files.txt ]]; then + mapfile -t excluded_generated_files < coverage/unit/excluded-generated-files.txt + lcov -r coverage/unit/lcov.output.srconly "${excluded_generated_files[@]}" -o coverage/unit/lcov.output.filtered --ignore-errors unused else cp -f coverage/unit/lcov.output.srconly coverage/unit/lcov.output.filtered fi @@ -173,9 +167,15 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: | lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.srconly - if [[ -s coverage/generated-source-patterns.txt ]]; then - mapfile -t generated_patterns < coverage/generated-source-patterns.txt - lcov -r coverage/integration/lcov.output.srconly "${generated_patterns[@]}" -o coverage/integration/lcov.output.filtered + awk -F: '/^SF:/{print $2}' coverage/integration/lcov.output.srconly | while read -r source_file; do + rel_path="${source_file#${{ github.workspace }}/}" + if [[ "${source_file}" == "${{ github.workspace }}/src/EnergyPlus/"* ]] && ! git -C "${{ github.workspace }}" ls-files --error-unmatch -- "${rel_path}" >/dev/null 2>&1; then + printf '%s\n' "${source_file}" + fi + done | sort -u > coverage/integration/excluded-generated-files.txt + if [[ -s coverage/integration/excluded-generated-files.txt ]]; then + mapfile -t excluded_generated_files < coverage/integration/excluded-generated-files.txt + lcov -r coverage/integration/lcov.output.srconly "${excluded_generated_files[@]}" -o coverage/integration/lcov.output.filtered --ignore-errors unused else cp -f coverage/integration/lcov.output.srconly coverage/integration/lcov.output.filtered fi From 8c7a16491119e3da110e3ec15e36a15b9c3ffbba Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 21 Apr 2026 20:23:22 -0600 Subject: [PATCH 07/19] is simpler better? --- .../workflows/self_hosted_build_and_test.yml | 55 +++++-------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 68e8fa258a5..d40ff693b11 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -47,8 +47,10 @@ jobs: with: path: | ${{ steps.setup-runner.outputs.ccache-dir }} - key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-${{ steps.checkout-sha.outputs.sha }}-coverage + key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref_name }}-${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} restore-keys: | + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref_name }}- + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}- ccache-self-hosted-linux- @@ -104,41 +106,22 @@ jobs: working-directory: ${{ env.BUILD_DIR }} run: mkdir -p coverage/unit coverage/integration - - name: Stage generated EnergyPlus sources for coverage - working-directory: ${{ env.BUILD_DIR }} - run: | - for generated in src/EnergyPlus/*.cc; do - [[ -e "${generated}" ]] || continue - target="${{ github.workspace }}/src/EnergyPlus/$(basename "${generated}")" - if [[ ! -e "${target}" ]]; then - cp -f "${generated}" "${target}" - fi - done - - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d ./src/EnergyPlus -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source + run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source,source - name: Generate filtered unit test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.srconly - awk -F: '/^SF:/{print $2}' coverage/unit/lcov.output.srconly | while read -r source_file; do - rel_path="${source_file#${{ github.workspace }}/}" - if [[ "${source_file}" == "${{ github.workspace }}/src/EnergyPlus/"* ]] && ! git -C "${{ github.workspace }}" ls-files --error-unmatch -- "${rel_path}" >/dev/null 2>&1; then - printf '%s\n' "${source_file}" - fi - done | sort -u > coverage/unit/excluded-generated-files.txt - if [[ -s coverage/unit/excluded-generated-files.txt ]]; then - mapfile -t excluded_generated_files < coverage/unit/excluded-generated-files.txt - lcov -r coverage/unit/lcov.output.srconly "${excluded_generated_files[@]}" -o coverage/unit/lcov.output.filtered --ignore-errors unused - else - cp -f coverage/unit/lcov.output.srconly coverage/unit/lcov.output.filtered + if ! lcov -r coverage/unit/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then + cp -f coverage/unit/lcov.output coverage/unit/lcov.output.filtered + elif ! grep -q '^SF:' coverage/unit/lcov.output.filtered; then + cp -f coverage/unit/lcov.output coverage/unit/lcov.output.filtered fi - name: Generate HTML unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage | tee coverage/unit/cover.txt + run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit @@ -161,28 +144,20 @@ jobs: - name: Generate raw integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d ./src/EnergyPlus -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source + run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source,source - name: Generate filtered integration test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.srconly - awk -F: '/^SF:/{print $2}' coverage/integration/lcov.output.srconly | while read -r source_file; do - rel_path="${source_file#${{ github.workspace }}/}" - if [[ "${source_file}" == "${{ github.workspace }}/src/EnergyPlus/"* ]] && ! git -C "${{ github.workspace }}" ls-files --error-unmatch -- "${rel_path}" >/dev/null 2>&1; then - printf '%s\n' "${source_file}" - fi - done | sort -u > coverage/integration/excluded-generated-files.txt - if [[ -s coverage/integration/excluded-generated-files.txt ]]; then - mapfile -t excluded_generated_files < coverage/integration/excluded-generated-files.txt - lcov -r coverage/integration/lcov.output.srconly "${excluded_generated_files[@]}" -o coverage/integration/lcov.output.filtered --ignore-errors unused - else - cp -f coverage/integration/lcov.output.srconly coverage/integration/lcov.output.filtered + if ! lcov -r coverage/integration/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then + cp -f coverage/integration/lcov.output coverage/integration/lcov.output.filtered + elif ! grep -q '^SF:' coverage/integration/lcov.output.filtered; then + cp -f coverage/integration/lcov.output coverage/integration/lcov.output.filtered fi - name: Generate HTML integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage | tee coverage/integration/cover.txt + run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration From 5356298a6c6bb121b79b96683cf307f926229958 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 22 Apr 2026 14:10:36 -0600 Subject: [PATCH 08/19] one more try --- .../workflows/self_hosted_build_and_test.yml | 13 +++++++++++- scripts/dev/gha_coverage_summary.py | 20 +++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index d40ff693b11..efe9f40e4f7 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -23,6 +23,9 @@ jobs: coverage: name: Coverage runs-on: [self-hosted, linux, x64, ubuntu-24.04] + permissions: + contents: read + statuses: write steps: - name: Checkout EnergyPlus uses: actions/checkout@v6 @@ -167,6 +170,7 @@ jobs: run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/cover.md >> "$GITHUB_STEP_SUMMARY" - name: Upload unit test coverage to Coveralls + id: coveralls-unit if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: @@ -176,8 +180,11 @@ jobs: flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} + git-branch: ${{ github.head_ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} - name: Upload integration test coverage to Coveralls + id: coveralls-integration if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: @@ -187,14 +194,18 @@ jobs: flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} + git-branch: ${{ github.head_ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} - name: Finish Coveralls coverage build - if: always() + if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || steps.coveralls-integration.conclusion == 'success') }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true build-number: ${{ github.run_id }} + git-branch: ${{ github.head_ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} - name: Upload unit test coverage artifacts if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} diff --git a/scripts/dev/gha_coverage_summary.py b/scripts/dev/gha_coverage_summary.py index f26991e1f44..10eb7da9b50 100644 --- a/scripts/dev/gha_coverage_summary.py +++ b/scripts/dev/gha_coverage_summary.py @@ -64,13 +64,25 @@ # lines......: 7.9% (28765 of 364658 lines) # functions......: 19.6% (2224 of 11327 functions) +import re from pathlib import Path + +def find_coverage_summary(lines: list[str], label: str) -> str: + pattern = re.compile(rf"^\s*{label}\.*:\s*(.+)$") + for line in reversed(lines): + match = pattern.match(line) + if match: + return match.group(1).strip() + tail = "\n".join(lines[-10:]) + raise RuntimeError(f"Could not find {label} coverage summary in cover.txt. Recent output:\n{tail}") + + cover_input = Path.cwd() / "cover.txt" -lines = cover_input.read_text().strip().split("\n") -line_coverage = lines[-2].strip().split(":")[1].strip() -line_percent = line_coverage.split(" ")[0] -function_coverage = lines[-1].strip().split(":")[1].strip() +lines = cover_input.read_text().splitlines() +line_coverage = find_coverage_summary(lines, "lines") +line_percent = line_coverage.split()[0] +function_coverage = find_coverage_summary(lines, "functions") cover_output = Path.cwd() / "cover.md" content = f"""
From d925fcd212c85ca07713efc8c00db0e40122e7de Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 22 Apr 2026 16:49:41 -0600 Subject: [PATCH 09/19] another try --- .../workflows/self_hosted_build_and_test.yml | 29 ++++++++++--------- scripts/dev/gha_coverage_summary.py | 23 ++++++++------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index efe9f40e4f7..00e9159cc0d 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -111,30 +111,30 @@ jobs: - name: Generate raw unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source,source + run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - name: Generate filtered unit test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - if ! lcov -r coverage/unit/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then - cp -f coverage/unit/lcov.output coverage/unit/lcov.output.filtered - elif ! grep -q '^SF:' coverage/unit/lcov.output.filtered; then + if ! lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then cp -f coverage/unit/lcov.output coverage/unit/lcov.output.filtered fi - name: Generate HTML unit test coverage results working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/unit/cover.txt + run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit - run: python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + continue-on-error: true + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py - name: Add unit test coverage summary to job summary + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/cover.md', github.workspace, env.BUILD_DIR)) != '' }} run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/cover.md >> "$GITHUB_STEP_SUMMARY" - name: Clear coverage counters before integration tests - run: python ${{ github.workspace }}/scripts/dev/clear_coverage_results.py ${{ env.BUILD_DIR }} + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/clear_coverage_results.py ${{ env.BUILD_DIR }} - name: Run integration tests excluding slowest and annual-only tests run: > @@ -147,26 +147,26 @@ jobs: - name: Generate raw integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ../src/EnergyPlus/ --ignore-errors source,source + run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - name: Generate filtered integration test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - if ! lcov -r coverage/integration/lcov.output "${{ github.workspace }}/${{ env.BUILD_DIR }}/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then - cp -f coverage/integration/lcov.output coverage/integration/lcov.output.filtered - elif ! grep -q '^SF:' coverage/integration/lcov.output.filtered; then + if ! lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then cp -f coverage/integration/lcov.output coverage/integration/lcov.output.filtered fi - name: Generate HTML integration test coverage results working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/integration/cover.txt + run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration - run: python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + continue-on-error: true + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py - name: Add integration test coverage summary to job summary + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/cover.md', github.workspace, env.BUILD_DIR)) != '' }} run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/cover.md >> "$GITHUB_STEP_SUMMARY" - name: Upload unit test coverage to Coveralls @@ -182,6 +182,7 @@ jobs: build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: false - name: Upload integration test coverage to Coveralls id: coveralls-integration @@ -196,6 +197,7 @@ jobs: build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: false - name: Finish Coveralls coverage build if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || steps.coveralls-integration.conclusion == 'success') }} @@ -206,6 +208,7 @@ jobs: build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: false - name: Upload unit test coverage artifacts if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} diff --git a/scripts/dev/gha_coverage_summary.py b/scripts/dev/gha_coverage_summary.py index 10eb7da9b50..97738809839 100644 --- a/scripts/dev/gha_coverage_summary.py +++ b/scripts/dev/gha_coverage_summary.py @@ -67,22 +67,23 @@ import re from pathlib import Path +ANSI_ESCAPE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]") -def find_coverage_summary(lines: list[str], label: str) -> str: - pattern = re.compile(rf"^\s*{label}\.*:\s*(.+)$") - for line in reversed(lines): - match = pattern.match(line) - if match: - return match.group(1).strip() - tail = "\n".join(lines[-10:]) + +def find_coverage_summary(text, label): + matches = re.findall(rf"^\s*{re.escape(label)}\.*:\s*(.+)$", text, re.MULTILINE) + if matches: + return matches[-1].strip() + tail = "\n".join(text.splitlines()[-10:]) raise RuntimeError(f"Could not find {label} coverage summary in cover.txt. Recent output:\n{tail}") cover_input = Path.cwd() / "cover.txt" -lines = cover_input.read_text().splitlines() -line_coverage = find_coverage_summary(lines, "lines") +cover_text = cover_input.read_text(encoding="utf-8", errors="replace") +cover_text = ANSI_ESCAPE.sub("", cover_text) +line_coverage = find_coverage_summary(cover_text, "lines") line_percent = line_coverage.split()[0] -function_coverage = find_coverage_summary(lines, "functions") +function_coverage = find_coverage_summary(cover_text, "functions") cover_output = Path.cwd() / "cover.md" content = f"""
@@ -91,4 +92,4 @@ def find_coverage_summary(lines: list[str], label: str) -> str: - {line_coverage} - {function_coverage}
""" -cover_output.write_text(content) +cover_output.write_text(content, encoding="utf-8") From e60cca8c52bfab6ed2df188ac7c951186dfa3e2c Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 10:07:37 -0600 Subject: [PATCH 10/19] another test --- .../workflows/self_hosted_build_and_test.yml | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 00e9159cc0d..0062c411284 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -10,6 +10,10 @@ on: required: false default: "" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref }} + cancel-in-progress: true + env: PYTHON_REQUIRED_VERSION: "3.12.2" FC: gfortran-13 @@ -60,7 +64,7 @@ jobs: - name: Install Linux coverage tools run: | sudo apt-get -qq update - sudo apt-get -qq install -y lcov gcovr + sudo apt-get -qq install -y lcov - name: Show restored ccache stats shell: bash @@ -88,7 +92,7 @@ jobs: -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF -DENABLE_PCH:BOOL=OFF -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON - -DCOMMIT_SHA:STRING="$(git rev-parse HEAD)" + -DCOMMIT_SHA:STRING=${{ steps.checkout-sha.outputs.sha }} - name: Build coverage targets run: cmake --build ${{ env.BUILD_DIR }} -j "${{ steps.setup-runner.outputs.nproc }}" @@ -105,24 +109,15 @@ jobs: --output-on-failure -j "${{ steps.setup-runner.outputs.nproc }}" - - name: Create coverage output directories - working-directory: ${{ env.BUILD_DIR }} - run: mkdir -p coverage/unit coverage/integration - - - name: Generate raw unit test coverage results - working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - - - name: Generate filtered unit test coverage results + - name: Generate unit test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - if ! lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then - cp -f coverage/unit/lcov.output coverage/unit/lcov.output.filtered - fi - - - name: Generate HTML unit test coverage results - working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt + mkdir -p coverage/unit + lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source + lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty + # Coveralls needs repo-relative SF paths to fetch source for line views. + sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/unit/lcov.output.filtered > coverage/unit/lcov.output.coveralls + genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit @@ -145,20 +140,15 @@ jobs: --output-on-failure -j "${{ steps.setup-runner.outputs.nproc }}" - - name: Generate raw integration test coverage results - working-directory: ${{ env.BUILD_DIR }} - run: lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - - - name: Generate filtered integration test coverage results + - name: Generate integration test coverage results working-directory: ${{ env.BUILD_DIR }} run: | - if ! lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty; then - cp -f coverage/integration/lcov.output coverage/integration/lcov.output.filtered - fi - - - name: Generate HTML integration test coverage results - working-directory: ${{ env.BUILD_DIR }} - run: genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt + mkdir -p coverage/integration + lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source + lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty + # Coveralls needs repo-relative SF paths to fetch source for line views. + sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/integration/lcov.output.filtered > coverage/integration/lcov.output.coveralls + genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration @@ -171,32 +161,34 @@ jobs: - name: Upload unit test coverage to Coveralls id: coveralls-unit - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.filtered + file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.coveralls format: lcov + base-path: ${{ github.workspace }} flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: false - name: Upload integration test coverage to Coveralls id: coveralls-integration - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.filtered + file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.coveralls format: lcov + base-path: ${{ github.workspace }} flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: false - name: Finish Coveralls coverage build @@ -207,7 +199,7 @@ jobs: parallel-finished: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: false - name: Upload unit test coverage artifacts @@ -217,6 +209,7 @@ jobs: name: unit_test_coverage_results path: | ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.filtered + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.coveralls ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov-html - name: Upload integration test coverage artifacts @@ -226,6 +219,7 @@ jobs: name: integration_test_coverage_results path: | ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.filtered + ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.coveralls ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov-html - name: Save ccache From c8272af699f40ba10e1f5d758760f785ca13b4ae Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 10:17:25 -0600 Subject: [PATCH 11/19] try to improve ccache hits --- .github/workflows/self_hosted_build_and_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 0062c411284..e795e526c6b 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -54,9 +54,9 @@ jobs: with: path: | ${{ steps.setup-runner.outputs.ccache-dir }} - key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref_name }}-${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.head_ref || github.event.inputs.ref || github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }} restore-keys: | - ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref_name }}- + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.head_ref || github.event.inputs.ref || github.ref_name }}- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}- ccache-self-hosted-linux- From a935d3502a59365f3cc7222d9177d211cb027b49 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 12:22:36 -0600 Subject: [PATCH 12/19] upload to coveralls --- .../workflows/self_hosted_build_and_test.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index e795e526c6b..6687e077f3a 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -171,9 +171,9 @@ jobs: flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ steps.checkout-sha.outputs.sha }} - fail-on-error: false + git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: true - name: Upload integration test coverage to Coveralls id: coveralls-integration @@ -187,9 +187,9 @@ jobs: flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ steps.checkout-sha.outputs.sha }} - fail-on-error: false + git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: true - name: Finish Coveralls coverage build if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || steps.coveralls-integration.conclusion == 'success') }} @@ -198,9 +198,9 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.ref_name }} - git-commit: ${{ steps.checkout-sha.outputs.sha }} - fail-on-error: false + git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} + git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + fail-on-error: true - name: Upload unit test coverage artifacts if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} From 1b25a927def7a98773d024201df628ecf9747ab5 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 13:25:47 -0600 Subject: [PATCH 13/19] another try --- .github/workflows/self_hosted_build_and_test.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 6687e077f3a..7927778d28e 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -112,12 +112,14 @@ jobs: - name: Generate unit test coverage results working-directory: ${{ env.BUILD_DIR }} run: | + set -o pipefail mkdir -p coverage/unit - lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty + lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --source-directory ${{ github.workspace }} --ignore-errors source,source + lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" "src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty + grep -q '^DA:' coverage/unit/lcov.output.filtered # Coveralls needs repo-relative SF paths to fetch source for line views. sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/unit/lcov.output.filtered > coverage/unit/lcov.output.coveralls - genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt + genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --source-directory ${{ github.workspace }} --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit @@ -143,12 +145,14 @@ jobs: - name: Generate integration test coverage results working-directory: ${{ env.BUILD_DIR }} run: | + set -o pipefail mkdir -p coverage/integration - lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --ignore-errors source,source - lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty + lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --source-directory ${{ github.workspace }} --ignore-errors source,source + lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" "src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty + grep -q '^DA:' coverage/integration/lcov.output.filtered # Coveralls needs repo-relative SF paths to fetch source for line views. sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/integration/lcov.output.filtered > coverage/integration/lcov.output.coveralls - genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt + genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --source-directory ${{ github.workspace }} --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration From 451ea4ac21fff651cda61aca46c170a303e65c69 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 14:48:16 -0600 Subject: [PATCH 14/19] try try again --- .../workflows/self_hosted_build_and_test.yml | 30 ++-- scripts/dev/normalize_lcov_paths.py | 149 ++++++++++++++++++ 2 files changed, 167 insertions(+), 12 deletions(-) create mode 100644 scripts/dev/normalize_lcov_paths.py diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 7927778d28e..abe5deaf6bf 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -114,12 +114,15 @@ jobs: run: | set -o pipefail mkdir -p coverage/unit - lcov -c -d . -o coverage/unit/lcov.output --no-external --base-directory ${{ github.workspace }} --source-directory ${{ github.workspace }} --ignore-errors source,source - lcov -e coverage/unit/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" "src/EnergyPlus/*" -o coverage/unit/lcov.output.filtered --ignore-errors unused,unused,empty,empty - grep -q '^DA:' coverage/unit/lcov.output.filtered - # Coveralls needs repo-relative SF paths to fetch source for line views. - sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/unit/lcov.output.filtered > coverage/unit/lcov.output.coveralls - genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --source-directory ${{ github.workspace }} --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/unit/cover.txt + lcov -c -d . -o coverage/unit/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source + ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python \ + ${{ github.workspace }}/scripts/dev/normalize_lcov_paths.py \ + coverage/unit/lcov.output \ + --workspace ${{ github.workspace }} \ + --build-directory ${{ github.workspace }}/${{ env.BUILD_DIR }} \ + --absolute-output coverage/unit/lcov.output.filtered \ + --relative-output coverage/unit/lcov.output.coveralls + genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit @@ -147,12 +150,15 @@ jobs: run: | set -o pipefail mkdir -p coverage/integration - lcov -c -d . -o coverage/integration/lcov.output --no-external --base-directory ${{ github.workspace }} --source-directory ${{ github.workspace }} --ignore-errors source,source - lcov -e coverage/integration/lcov.output "${{ github.workspace }}/src/EnergyPlus/*" "src/EnergyPlus/*" -o coverage/integration/lcov.output.filtered --ignore-errors unused,unused,empty,empty - grep -q '^DA:' coverage/integration/lcov.output.filtered - # Coveralls needs repo-relative SF paths to fetch source for line views. - sed "s#^SF:${{ github.workspace }}/#SF:#" coverage/integration/lcov.output.filtered > coverage/integration/lcov.output.coveralls - genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --source-directory ${{ github.workspace }} --demangle-cpp --function-coverage --synthesize-missing --ignore-errors source,source | tee coverage/integration/cover.txt + lcov -c -d . -o coverage/integration/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source + ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python \ + ${{ github.workspace }}/scripts/dev/normalize_lcov_paths.py \ + coverage/integration/lcov.output \ + --workspace ${{ github.workspace }} \ + --build-directory ${{ github.workspace }}/${{ env.BUILD_DIR }} \ + --absolute-output coverage/integration/lcov.output.filtered \ + --relative-output coverage/integration/lcov.output.coveralls + genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration diff --git a/scripts/dev/normalize_lcov_paths.py b/scripts/dev/normalize_lcov_paths.py new file mode 100644 index 00000000000..345c9b125e3 --- /dev/null +++ b/scripts/dev/normalize_lcov_paths.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +import argparse +import sys +from pathlib import Path + + +def build_source_index(workspace: Path) -> dict[str, list[Path]]: + source_index: dict[str, list[Path]] = {} + source_root = workspace / "src" / "EnergyPlus" + for source_file in source_root.rglob("*"): + if source_file.is_file(): + relative_path = source_file.relative_to(workspace) + source_index.setdefault(source_file.name, []).append(relative_path) + return source_index + + +def repo_relative_source( + source_file: str, + workspace: Path, + build_directory: Path | None, + source_index: dict[str, list[Path]], +) -> Path | None: + source_path = Path(source_file) + candidates: list[Path] = [] + + if source_path.is_absolute(): + candidates.append(source_path) + else: + candidates.append(workspace / source_path) + if build_directory is not None: + candidates.append(build_directory / source_path) + + for candidate in candidates: + try: + relative_path = candidate.resolve().relative_to(workspace.resolve()) + except ValueError: + continue + + parts = relative_path.parts + for index in range(len(parts) - 1): + if parts[index] == "src" and parts[index + 1] == "EnergyPlus": + relative_path = Path(*parts[index:]) + break + + if not relative_path.as_posix().startswith("src/EnergyPlus/"): + continue + + if (workspace / relative_path).is_file(): + return relative_path + + basename_matches = source_index.get(source_path.name, []) + if len(basename_matches) == 1: + return basename_matches[0] + + return None + + +def flush_record( + record_lines: list[str], + relative_source: Path | None, + workspace: Path, + absolute_records: list[str], + relative_records: list[str], +) -> int: + if relative_source is None: + return 0 + + da_lines = sum(1 for line in record_lines if line.startswith("DA:")) + if da_lines == 0: + return 0 + + absolute_source = (workspace / relative_source).as_posix() + relative_source_text = relative_source.as_posix() + + for line in record_lines: + if line.startswith("SF:"): + absolute_records.append(f"SF:{absolute_source}") + relative_records.append(f"SF:{relative_source_text}") + else: + absolute_records.append(line) + relative_records.append(line) + + return da_lines + + +def normalize_lcov_paths( + input_file: Path, + workspace: Path, + build_directory: Path | None, + absolute_output: Path, + relative_output: Path, +) -> int: + source_index = build_source_index(workspace) + absolute_records: list[str] = [] + relative_records: list[str] = [] + record_lines: list[str] = [] + relative_source: Path | None = None + da_lines = 0 + + with input_file.open("r", encoding="utf-8") as input_stream: + for raw_line in input_stream: + line = raw_line.rstrip("\n") + if line.startswith("SF:"): + relative_source = repo_relative_source(line[3:], workspace, build_directory, source_index) + record_lines.append(line) + elif line == "end_of_record": + record_lines.append(line) + da_lines += flush_record(record_lines, relative_source, workspace, absolute_records, relative_records) + record_lines = [] + relative_source = None + else: + record_lines.append(line) + + absolute_output.parent.mkdir(parents=True, exist_ok=True) + relative_output.parent.mkdir(parents=True, exist_ok=True) + absolute_output.write_text("\n".join(absolute_records) + ("\n" if absolute_records else ""), encoding="utf-8") + relative_output.write_text("\n".join(relative_records) + ("\n" if relative_records else ""), encoding="utf-8") + + return da_lines + + +def main() -> int: + parser = argparse.ArgumentParser(description="Filter LCOV records to real repo source files and normalize SF paths.") + parser.add_argument("input_file", type=Path) + parser.add_argument("--workspace", type=Path, required=True) + parser.add_argument("--build-directory", type=Path) + parser.add_argument("--absolute-output", type=Path, required=True) + parser.add_argument("--relative-output", type=Path, required=True) + args = parser.parse_args() + + da_lines = normalize_lcov_paths( + input_file=args.input_file, + workspace=args.workspace, + build_directory=args.build_directory, + absolute_output=args.absolute_output, + relative_output=args.relative_output, + ) + + if da_lines == 0: + print("No LCOV data records matched real files under src/EnergyPlus", file=sys.stderr) + return 1 + + print(f"Wrote normalized LCOV data with {da_lines} DA records") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 743a7c5148230129d6f531a8f3207fc032bb78a5 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sat, 25 Apr 2026 19:40:18 -0600 Subject: [PATCH 15/19] one more --- .../workflows/self_hosted_build_and_test.yml | 118 ++++++++++-------- scripts/dev/normalize_lcov_paths.py | 7 ++ 2 files changed, 73 insertions(+), 52 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index abe5deaf6bf..7481277ab59 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -11,7 +11,8 @@ on: default: "" concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.inputs.ref || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || + github.event.inputs.ref || github.ref }} cancel-in-progress: true env: @@ -26,7 +27,7 @@ env: jobs: coverage: name: Coverage - runs-on: [self-hosted, linux, x64, ubuntu-24.04] + runs-on: [ self-hosted, linux, x64, ubuntu-24.04 ] permissions: contents: read statuses: write @@ -54,7 +55,9 @@ jobs: with: path: | ${{ steps.setup-runner.outputs.ccache-dir }} - key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.head_ref || github.event.inputs.ref || github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }} + key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id + }}-coverage-${{ github.head_ref || github.event.inputs.ref || + github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }} restore-keys: | ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.head_ref || github.event.inputs.ref || github.ref_name }}- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage- @@ -75,27 +78,21 @@ jobs: - name: Configure coverage build run: > - cmake -S . -B ${{ env.BUILD_DIR }} - -G "Unix Makefiles" - -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DLINK_WITH_PYTHON:BOOL=ON - -DPYTHON_CLI:BOOL=OFF - -DPython_REQUIRED_VERSION:STRING=${{ env.PYTHON_REQUIRED_VERSION }} - -DPython_ROOT_DIR:PATH=${{ steps.setup-runner.outputs.python-root-dir }} - -DBUILD_FORTRAN:BOOL=ON - -DBUILD_TESTING=ON - -DBUILD_PACKAGE=OFF - -DDOCUMENTATION_BUILD=DoNotBuild - -DENABLE_REGRESSION_TESTING:BOOL=OFF - -DTEST_ANNUAL_SIMULATION:BOOL=OFF - -DENABLE_COVERAGE:BOOL=ON - -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF - -DENABLE_PCH:BOOL=OFF - -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON - -DCOMMIT_SHA:STRING=${{ steps.checkout-sha.outputs.sha }} + cmake -S . -B ${{ env.BUILD_DIR }} -G "Unix Makefiles" + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLINK_WITH_PYTHON:BOOL=ON + -DPYTHON_CLI:BOOL=OFF -DPython_REQUIRED_VERSION:STRING=${{ + env.PYTHON_REQUIRED_VERSION }} -DPython_ROOT_DIR:PATH=${{ + steps.setup-runner.outputs.python-root-dir }} -DBUILD_FORTRAN:BOOL=ON + -DBUILD_TESTING=ON -DBUILD_PACKAGE=OFF + -DDOCUMENTATION_BUILD=DoNotBuild -DENABLE_REGRESSION_TESTING:BOOL=OFF + -DTEST_ANNUAL_SIMULATION:BOOL=OFF -DENABLE_COVERAGE:BOOL=ON + -DENABLE_GTEST_DEBUG_MODE:BOOL=OFF -DENABLE_PCH:BOOL=OFF + -DFORCE_DEBUG_ARITHM_GCC_OR_CLANG:BOOL=ON -DCOMMIT_SHA:STRING=${{ + steps.checkout-sha.outputs.sha }} - name: Build coverage targets - run: cmake --build ${{ env.BUILD_DIR }} -j "${{ steps.setup-runner.outputs.nproc }}" + run: cmake --build ${{ env.BUILD_DIR }} -j "${{ steps.setup-runner.outputs.nproc + }}" - name: Show post-build ccache stats shell: bash @@ -103,18 +100,15 @@ jobs: - name: Run unit tests run: > - ctest - --test-dir ${{ env.BUILD_DIR }} - -E "integration.*" - --output-on-failure - -j "${{ steps.setup-runner.outputs.nproc }}" + ctest --test-dir ${{ env.BUILD_DIR }} -E "integration.*" + --output-on-failure -j "${{ steps.setup-runner.outputs.nproc }}" - name: Generate unit test coverage results working-directory: ${{ env.BUILD_DIR }} run: | set -o pipefail mkdir -p coverage/unit - lcov -c -d . -o coverage/unit/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source + lcov -c -d . -o coverage/unit/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source,mismatch,mismatch ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python \ ${{ github.workspace }}/scripts/dev/normalize_lcov_paths.py \ coverage/unit/lcov.output \ @@ -127,30 +121,33 @@ jobs: - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit continue-on-error: true - run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ + github.workspace }}/scripts/dev/gha_coverage_summary.py - name: Add unit test coverage summary to job summary - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/cover.md', github.workspace, env.BUILD_DIR)) != '' }} - run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/cover.md >> "$GITHUB_STEP_SUMMARY" + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/cover.md', + github.workspace, env.BUILD_DIR)) != '' }} + run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/cover.md >> + "$GITHUB_STEP_SUMMARY" - name: Clear coverage counters before integration tests - run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/clear_coverage_results.py ${{ env.BUILD_DIR }} + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ + github.workspace }}/scripts/dev/clear_coverage_results.py ${{ + env.BUILD_DIR }} - name: Run integration tests excluding slowest and annual-only tests run: > - ctest - --test-dir ${{ env.BUILD_DIR }} - -R "integration.*" - -E "${{ env.INTEGRATION_EXCLUDE_REGEX }}|${{ env.ANNUAL_SIMULATION_EXCLUDE_REGEX }}" - --output-on-failure - -j "${{ steps.setup-runner.outputs.nproc }}" + ctest --test-dir ${{ env.BUILD_DIR }} -R "integration.*" -E "${{ + env.INTEGRATION_EXCLUDE_REGEX }}|${{ + env.ANNUAL_SIMULATION_EXCLUDE_REGEX }}" --output-on-failure -j "${{ + steps.setup-runner.outputs.nproc }}" - name: Generate integration test coverage results working-directory: ${{ env.BUILD_DIR }} run: | set -o pipefail mkdir -p coverage/integration - lcov -c -d . -o coverage/integration/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source + lcov -c -d . -o coverage/integration/lcov.output --base-directory ${{ github.workspace }} --ignore-errors source,source,mismatch,mismatch ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python \ ${{ github.workspace }}/scripts/dev/normalize_lcov_paths.py \ coverage/integration/lcov.output \ @@ -163,57 +160,72 @@ jobs: - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration continue-on-error: true - run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ github.workspace }}/scripts/dev/gha_coverage_summary.py + run: ${{ steps.setup-runner.outputs.python-root-dir }}/bin/python ${{ + github.workspace }}/scripts/dev/gha_coverage_summary.py - name: Add integration test coverage summary to job summary - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/cover.md', github.workspace, env.BUILD_DIR)) != '' }} - run: cat ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/cover.md >> "$GITHUB_STEP_SUMMARY" + if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/cover.md', + github.workspace, env.BUILD_DIR)) != '' }} + run: cat ${{ github.workspace }}/${{ env.BUILD_DIR + }}/coverage/integration/cover.md >> "$GITHUB_STEP_SUMMARY" - name: Upload unit test coverage to Coveralls id: coveralls-unit - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && + hashFiles(format('{0}/{1}/coverage/unit/lcov.output.coveralls', + github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.coveralls + file: ${{ github.workspace }}/${{ env.BUILD_DIR + }}/coverage/unit/lcov.output.coveralls format: lcov base-path: ${{ github.workspace }} flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ github.event.pull_request.head.sha || + steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Upload integration test coverage to Coveralls id: coveralls-integration - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && + hashFiles(format('{0}/{1}/coverage/integration/lcov.output.coveralls', + github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.coveralls + file: ${{ github.workspace }}/${{ env.BUILD_DIR + }}/coverage/integration/lcov.output.coveralls format: lcov base-path: ${{ github.workspace }} flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ github.event.pull_request.head.sha || + steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Finish Coveralls coverage build - if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || steps.coveralls-integration.conclusion == 'success') }} + if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || + steps.coveralls-integration.conclusion == 'success') }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true build-number: ${{ github.run_id }} git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || steps.checkout-sha.outputs.sha }} + git-commit: ${{ github.event.pull_request.head.sha || + steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Upload unit test coverage artifacts - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && + hashFiles(format('{0}/{1}/coverage/unit/lcov.output.filtered', + github.workspace, env.BUILD_DIR)) != '' }} uses: actions/upload-artifact@v4 with: name: unit_test_coverage_results @@ -223,7 +235,9 @@ jobs: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov-html - name: Upload integration test coverage artifacts - if: ${{ always() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', github.workspace, env.BUILD_DIR)) != '' }} + if: ${{ always() && + hashFiles(format('{0}/{1}/coverage/integration/lcov.output.filtered', + github.workspace, env.BUILD_DIR)) != '' }} uses: actions/upload-artifact@v4 with: name: integration_test_coverage_results diff --git a/scripts/dev/normalize_lcov_paths.py b/scripts/dev/normalize_lcov_paths.py index 345c9b125e3..91969fc875a 100644 --- a/scripts/dev/normalize_lcov_paths.py +++ b/scripts/dev/normalize_lcov_paths.py @@ -24,6 +24,13 @@ def repo_relative_source( source_path = Path(source_file) candidates: list[Path] = [] + source_parts = source_path.parts + for index in range(len(source_parts) - 1): + if source_parts[index] == "src" and source_parts[index + 1] == "EnergyPlus": + relative_path = Path(*source_parts[index:]) + if (workspace / relative_path).is_file(): + return relative_path + if source_path.is_absolute(): candidates.append(source_path) else: From 1c43862cf90777581bbd43c8d5335f810a258f3a Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sun, 26 Apr 2026 20:07:09 -0600 Subject: [PATCH 16/19] unmapped error --- .github/workflows/self_hosted_build_and_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 7481277ab59..831205bb030 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -116,7 +116,7 @@ jobs: --build-directory ${{ github.workspace }}/${{ env.BUILD_DIR }} \ --absolute-output coverage/unit/lcov.output.filtered \ --relative-output coverage/unit/lcov.output.coveralls - genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/unit/cover.txt + genhtml coverage/unit/lcov.output.filtered -o coverage/unit/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source,unmapped,unmapped | tee coverage/unit/cover.txt - name: Process unit test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/unit @@ -155,7 +155,7 @@ jobs: --build-directory ${{ github.workspace }}/${{ env.BUILD_DIR }} \ --absolute-output coverage/integration/lcov.output.filtered \ --relative-output coverage/integration/lcov.output.coveralls - genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source | tee coverage/integration/cover.txt + genhtml coverage/integration/lcov.output.filtered -o coverage/integration/lcov-html --demangle-cpp --function-coverage --ignore-errors source,source,unmapped,unmapped | tee coverage/integration/cover.txt - name: Process integration test coverage summary working-directory: ${{ env.BUILD_DIR }}/coverage/integration From 508ae8f174f060ba82c1792f731af8732f6a0a12 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Sun, 26 Apr 2026 21:17:16 -0600 Subject: [PATCH 17/19] fix drift --- .../workflows/self_hosted_build_and_test.yml | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 831205bb030..9dc226c5cc5 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -1,8 +1,9 @@ name: Self-Hosted Build and Test on: - pull_request: - branches: [ develop ] + push: + branches: + - "**" workflow_dispatch: inputs: ref: @@ -11,8 +12,7 @@ on: default: "" concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || - github.event.inputs.ref || github.ref }} + group: ${{ github.workflow }}-${{ github.event.inputs.ref || github.ref }} cancel-in-progress: true env: @@ -56,10 +56,10 @@ jobs: path: | ${{ steps.setup-runner.outputs.ccache-dir }} key: ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id - }}-coverage-${{ github.head_ref || github.event.inputs.ref || - github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }} + }}-coverage-${{ github.event.inputs.ref || github.ref_name }}-${{ + github.run_id }}-${{ github.run_attempt }} restore-keys: | - ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.head_ref || github.event.inputs.ref || github.ref_name }}- + ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage-${{ github.event.inputs.ref || github.ref_name }}- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}-coverage- ccache-self-hosted-linux-${{ steps.setup-runner.outputs.compiler-id }}- ccache-self-hosted-linux- @@ -184,9 +184,8 @@ jobs: flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || - steps.checkout-sha.outputs.sha }} + git-branch: ${{ github.event.inputs.ref || github.ref_name }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Upload integration test coverage to Coveralls @@ -204,9 +203,8 @@ jobs: flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || - steps.checkout-sha.outputs.sha }} + git-branch: ${{ github.event.inputs.ref || github.ref_name }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Finish Coveralls coverage build @@ -217,9 +215,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true build-number: ${{ github.run_id }} - git-branch: ${{ github.head_ref || github.event.inputs.ref || github.ref_name }} - git-commit: ${{ github.event.pull_request.head.sha || - steps.checkout-sha.outputs.sha }} + git-branch: ${{ github.event.inputs.ref || github.ref_name }} + git-commit: ${{ steps.checkout-sha.outputs.sha }} fail-on-error: true - name: Upload unit test coverage artifacts From 517168e655236c240c81f475e6977efc2f53211f Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Mon, 27 Apr 2026 08:15:25 -0600 Subject: [PATCH 18/19] fix base path --- .github/workflows/self_hosted_build_and_test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 9dc226c5cc5..99038cbbb5d 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -180,7 +180,6 @@ jobs: file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/unit/lcov.output.coveralls format: lcov - base-path: ${{ github.workspace }} flag-name: unit-tests parallel: true build-number: ${{ github.run_id }} @@ -199,7 +198,6 @@ jobs: file: ${{ github.workspace }}/${{ env.BUILD_DIR }}/coverage/integration/lcov.output.coveralls format: lcov - base-path: ${{ github.workspace }} flag-name: integration-tests parallel: true build-number: ${{ github.run_id }} From 52a835ad70dee70f85fc778e335b3d8ecd982b97 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Mon, 27 Apr 2026 11:34:27 -0600 Subject: [PATCH 19/19] only run on successful jobs --- .github/workflows/self_hosted_build_and_test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/self_hosted_build_and_test.yml b/.github/workflows/self_hosted_build_and_test.yml index 99038cbbb5d..20909d33fe8 100644 --- a/.github/workflows/self_hosted_build_and_test.yml +++ b/.github/workflows/self_hosted_build_and_test.yml @@ -171,7 +171,7 @@ jobs: - name: Upload unit test coverage to Coveralls id: coveralls-unit - if: ${{ always() && + if: ${{ success() && hashFiles(format('{0}/{1}/coverage/unit/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 @@ -189,7 +189,7 @@ jobs: - name: Upload integration test coverage to Coveralls id: coveralls-integration - if: ${{ always() && + if: ${{ success() && hashFiles(format('{0}/{1}/coverage/integration/lcov.output.coveralls', github.workspace, env.BUILD_DIR)) != '' }} uses: coverallsapp/github-action@v2 @@ -206,8 +206,8 @@ jobs: fail-on-error: true - name: Finish Coveralls coverage build - if: ${{ always() && (steps.coveralls-unit.conclusion == 'success' || - steps.coveralls-integration.conclusion == 'success') }} + if: ${{ success() && steps.coveralls-unit.conclusion == 'success' && + steps.coveralls-integration.conclusion == 'success' }} uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }}