# ==================================================================================================================== # # Authors: # # Patrick Lehmann # # # # ==================================================================================================================== # # Copyright 2020-2025 The pyTooling Authors # # # # Licensed under the Apache License, Version 2.0 (the "License"); # # you may not use this file except in compliance with the License. # # You may obtain a copy of the License at # # # # http://www.apache.org/licenses/LICENSE-2.0 # # # # Unless required by applicable law or agreed to in writing, software # # distributed under the License is distributed on an "AS IS" BASIS, # # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # # See the License for the specific language governing permissions and # # limitations under the License. # # # # SPDX-License-Identifier: Apache-2.0 # # ==================================================================================================================== # name: Publish Code Coverage Results on: workflow_call: inputs: ubuntu_image_version: description: 'Ubuntu image version.' required: false default: '24.04' type: string coverage_artifacts_pattern: required: false default: '*-CodeCoverage-SQLite-*' type: string coverage_config: description: 'Path to the .coveragerc file. Use pyproject.toml by default.' required: false default: 'pyproject.toml' type: string coverage_sqlite_artifact: description: 'Name of the SQLite coverage artifact.' required: false default: '' type: string coverage_xml_artifact: description: 'Name of the XML coverage artifact.' required: false default: '' type: string coverage_report_xml_directory: description: 'Directory containing the XML coverage report file.' required: false default: 'report/coverage' type: string coverage_report_xml_filename: description: 'Filename of the XML coverage report file.' required: false default: 'coverage.xml' type: string coverage_json_artifact: description: 'Name of the JSON coverage artifact.' required: false default: '' type: string coverage_report_json_directory: description: 'Directory containing the JSON coverage report file.' required: false default: 'report/coverage' type: string coverage_report_json_filename: description: 'Filename of the JSON coverage report file.' required: false default: 'coverage.json' type: string coverage_html_artifact: description: 'Name of the HTML coverage artifact.' required: false default: '' type: string coverage_report_html_directory: description: 'HTML root directory of the generated coverage report.' required: false default: 'report/coverage/html' type: string codecov: description: 'Publish merged coverage report to Codecov.' required: false default: 'false' type: string codacy: description: 'Publish merged coverage report to Codacy.' required: false default: 'false' type: string secrets: CODECOV_TOKEN: description: 'Token to push result to Codecov.' required: false CODACY_TOKEN: description: 'Token to push result to Codacy.' required: false jobs: PublishCoverageResults: name: 📊 Publish Code Coverage Results runs-on: "ubuntu-${{ inputs.ubuntu_image_version }}" if: always() steps: - name: ⏬ Checkout repository uses: actions/checkout@v5 with: lfs: true submodules: true - name: 📥 Download Artifacts uses: pyTooling/download-artifact@v5 with: pattern: ${{ inputs.coverage_artifacts_pattern }} path: artifacts - name: 🔎 Inspect extracted artifact (tarball) run: | tree -pash artifacts - name: 🔧 Install coverage and tomli run: | python -m pip install -U --disable-pip-version-check --break-system-packages coverage[toml] tomli - name: Rename .coverage files and move them all into 'coverage/' run: | mkdir -p coverage find artifacts/ -type f -path "*SQLite*.coverage" -exec sh -c 'cp -v $0 "coverage/$(basename $0).$(basename $(dirname $0))"' {} ';' tree -pash coverage - name: Combine SQLite files (using Coverage.py) run: coverage combine --data-file=.coverage coverage/ - name: Report code coverage run: coverage report --rcfile=pyproject.toml --data-file=.coverage - name: Convert to XML format (Cobertura) if: inputs.coverage_xml_artifact != '' || inputs.codecov || inputs.codacy run: coverage xml --data-file=.coverage - name: Convert to JSON format if: inputs.coverage_json_artifact != '' run: coverage json --data-file=.coverage - name: Convert to HTML format if: inputs.coverage_html_artifact != '' run: | coverage html --data-file=.coverage -d report/coverage/html rm report/coverage/html/.gitignore tree -pash report/coverage/html - name: 📤 Upload 'Coverage SQLite Database' artifact uses: pyTooling/upload-artifact@v4 if: inputs.coverage_sqlite_artifact != '' continue-on-error: true with: name: ${{ inputs.coverage_sqlite_artifact }} path: .coverage if-no-files-found: error retention-days: 1 - name: 📤 Upload 'Coverage XML Report' artifact uses: pyTooling/upload-artifact@v4 if: inputs.coverage_xml_artifact != '' continue-on-error: true with: name: ${{ inputs.coverage_xml_artifact }} working-directory: ${{ inputs.coverage_report_xml_directory }} path: ${{ inputs.coverage_report_xml_filename }} if-no-files-found: error retention-days: 1 - name: 📤 Upload 'Coverage JSON Report' artifact uses: pyTooling/upload-artifact@v4 if: inputs.coverage_json_artifact != '' continue-on-error: true with: name: ${{ inputs.coverage_json_artifact }} working-directory: ${{ inputs.coverage_report_json_directory }} path: ${{ inputs.coverage_report_json_filename }} if-no-files-found: error retention-days: 1 - name: 📤 Upload 'Coverage HTML Report' artifact uses: pyTooling/upload-artifact@v4 if: inputs.coverage_html_artifact != '' continue-on-error: true with: name: ${{ inputs.coverage_html_artifact }} working-directory: ${{ inputs.coverage_report_html_directory }} path: '*' if-no-files-found: error retention-days: 1 - name: 📊 Publish code coverage at CodeCov uses: codecov/codecov-action@v5 id: codecov if: inputs.codecov == 'true' continue-on-error: true with: token: ${{ secrets.CODECOV_TOKEN }} disable_search: true files: ${{ inputs.coverage_report_xml_directory }}/${{ inputs.coverage_report_xml_filename }} flags: unittests env_vars: PYTHON fail_ci_if_error: true - name: 📉 Publish code coverage at Codacy uses: codacy/codacy-coverage-reporter-action@v1 id: codacy if: inputs.codacy == 'true' continue-on-error: true with: project-token: ${{ secrets.CODACY_TOKEN }} coverage-reports: ${{ inputs.coverage_report_xml_directory }}/${{ inputs.coverage_report_xml_filename }} - name: Generate error messages run: | if [[ "${{ steps.codecov.outcome }}" == "failure" ]]; then printf "::error title=%s::%s\n" "Publish Code Coverage Results / Codecov" "Failed to publish code coverage results." else printf "Codecov: No errors to report.\n" fi if [[ "${{ steps.codacy.outcome }}" == "failure" ]]; then printf "::error title=%s::%s\n" "Publish Code Coverage Results / Codacy" "Failed to publish code coverage results." else printf "Codacy: No errors to report.\n" fi