1name: Code Coverage with codecov 2 3on: 4 push: 5 branches: 6 - main 7 - v*-branch 8 - collab-* 9 10permissions: 11 contents: read 12 13concurrency: 14 group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} 15 cancel-in-progress: true 16 17jobs: 18 codecov: 19 if: github.repository_owner == 'zephyrproject-rtos' 20 runs-on: 21 group: zephyr-runner-v2-linux-x64-4xlarge 22 container: 23 image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.7.20251127 24 options: '--entrypoint /bin/bash' 25 strategy: 26 fail-fast: false 27 matrix: 28 platform: ["mps2/an385", "native_sim", "qemu_x86", "unit_testing"] 29 include: 30 - platform: 'mps2/an385' 31 normalized: 'mps2_an385' 32 - platform: 'native_sim' 33 normalized: 'native_sim' 34 - platform: 'qemu_x86' 35 normalized: 'qemu_x86' 36 - platform: 'unit_testing' 37 normalized: 'unit_testing' 38 env: 39 CCACHE_DIR: /node-cache/ccache-zephyr 40 CCACHE_REMOTE_STORAGE: "redis://cache-*.keydb-cache.svc.cluster.local|shards=1,2,3" 41 CCACHE_REMOTE_ONLY: "true" 42 # `--specs` is ignored because ccache is unable to resovle the toolchain specs file path. 43 CCACHE_IGNOREOPTIONS: '-specs=* --specs=*' 44 steps: 45 - name: Apply container owner mismatch workaround 46 run: | 47 # FIXME: The owner UID of the GITHUB_WORKSPACE directory may not 48 # match the container user UID because of the way GitHub 49 # Actions runner is implemented. Remove this workaround when 50 # GitHub comes up with a fundamental fix for this problem. 51 git config --global --add safe.directory ${GITHUB_WORKSPACE} 52 53 - name: Print cloud service information 54 run: | 55 echo "ZEPHYR_RUNNER_CLOUD_PROVIDER = ${ZEPHYR_RUNNER_CLOUD_PROVIDER}" 56 echo "ZEPHYR_RUNNER_CLOUD_NODE = ${ZEPHYR_RUNNER_CLOUD_NODE}" 57 echo "ZEPHYR_RUNNER_CLOUD_POD = ${ZEPHYR_RUNNER_CLOUD_POD}" 58 59 - name: Update PATH for west 60 run: | 61 echo "$HOME/.local/bin" >> $GITHUB_PATH 62 63 - name: Clone cached Zephyr repository 64 continue-on-error: true 65 run: | 66 git clone --shared /repo-cache/zephyrproject/zephyr . 67 git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} 68 69 - name: checkout 70 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 71 with: 72 fetch-depth: 0 73 74 - name: Set up Python 75 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 76 with: 77 python-version: 3.12 78 cache: pip 79 cache-dependency-path: scripts/requirements-actions.txt 80 81 - name: Install Python packages 82 run: | 83 pip install -r scripts/requirements-actions.txt --require-hashes 84 85 - name: west setup 86 run: | 87 west init -l . || true 88 west update 1> west.update.log || west update 1> west.update-2.log 89 90 - name: Environment Setup 91 run: | 92 cmake --version 93 gcc --version 94 ls -la 95 96 echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV 97 98 - name: Set up ccache 99 run: | 100 mkdir -p ${CCACHE_DIR} 101 ccache -M 10G 102 ccache -p 103 ccache -z -s -vv 104 105 - name: Run Tests with Twister (Push) 106 continue-on-error: true 107 run: | 108 export ZEPHYR_BASE=${PWD} 109 export ZEPHYR_TOOLCHAIN_VARIANT=zephyr 110 mkdir -p coverage/reports 111 ./scripts/twister --save-tests ${{matrix.normalized}}-testplan.json 112 ls -la 113 ./scripts/twister \ 114 -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage \ 115 -T tests --coverage-tool gcovr -xCONFIG_TEST_EXTRA_STACK_SIZE=4096 -e nano \ 116 --timeout-multiplier 2 117 118 - name: Build Doxygen Coverage 119 if: matrix.platform == 'unit_testing' 120 run: | 121 pip install -r doc/requirements.txt --require-hashes 122 sudo apt-get update 123 sudo apt-get install -y graphviz # dot is needed but currently missing from the Docker image 124 cmake -B doc/_build -S doc 125 cmake --build doc/_build --target doxygen-coverage 126 127 - name: Upload Doxygen Coverage Results 128 if: matrix.platform == 'unit_testing' 129 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 130 with: 131 name: doxygen-coverage-results 132 path: | 133 doc/_build/new.info 134 doc/_build/coverage-report 135 136 - name: Print ccache stats 137 if: always() 138 run: | 139 ccache -s -vv 140 141 - name: Rename coverage files 142 if: always() 143 run: | 144 mv twister-out/coverage.json coverage/reports/${{matrix.normalized}}.json 145 146 - name: Upload Coverage Results 147 if: always() 148 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 149 with: 150 name: Coverage Data (Subset ${{ matrix.normalized }}) 151 path: | 152 coverage/reports/${{ matrix.normalized }}.json 153 ${{ matrix.normalized }}-testplan.json 154 155 codecov-results: 156 name: "Publish Coverage Results" 157 needs: codecov 158 runs-on: ubuntu-24.04 159 # the codecov job might be skipped, we don't need to run this job then 160 if: success() || failure() 161 162 steps: 163 - name: checkout 164 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 165 with: 166 fetch-depth: 0 167 168 - name: Set up Python 169 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 170 with: 171 python-version: 3.12 172 cache: pip 173 cache-dependency-path: scripts/requirements-actions.txt 174 175 - name: Install Python packages 176 run: | 177 pip install -r scripts/requirements-actions.txt --require-hashes 178 179 - name: Download Artifacts 180 uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 181 with: 182 path: coverage/reports 183 184 - name: Move coverage files 185 run: | 186 ls -lRt ./coverage/reports 187 mv ./coverage/reports/*/*testplan.json . 188 mv ./coverage/reports/*/coverage/reports/*.json ./coverage/reports 189 ls -la ./coverage/reports 190 191 - name: Generate list of coverage files 192 id: get-coverage-files 193 shell: cmake -P {0} 194 run: | 195 file(GLOB INPUT_FILES_LIST "coverage/reports/*.json") 196 set(MERGELIST "") 197 set(FILELIST "") 198 foreach(ITEM ${INPUT_FILES_LIST}) 199 get_filename_component(f ${ITEM} NAME) 200 if(FILELIST STREQUAL "") 201 set(FILELIST "${f}") 202 else() 203 set(FILELIST "${FILELIST},${f}") 204 endif() 205 endforeach() 206 foreach(ITEM ${INPUT_FILES_LIST}) 207 get_filename_component(f ${ITEM} NAME) 208 if(MERGELIST STREQUAL "") 209 set(MERGELIST "--add-tracefile ${f}") 210 else() 211 set(MERGELIST "${MERGELIST} -a ${f}") 212 endif() 213 endforeach() 214 file(APPEND $ENV{GITHUB_OUTPUT} "mergefiles=${MERGELIST}\n") 215 file(APPEND $ENV{GITHUB_OUTPUT} "covfiles=${FILELIST}\n") 216 217 - name: Merge coverage files 218 run: | 219 pushd ./coverage/reports 220 gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --json merged.json 221 gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --cobertura merged.xml 222 popd 223 224 - name: Get current date 225 id: run_date 226 run: | 227 echo "run_date=$(date --iso-8601=minutes)" >> "$GITHUB_OUTPUT" 228 echo "run_date_short=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT" 229 echo "run_date_year=$(date +'%Y')" >> "$GITHUB_OUTPUT" 230 echo "run_date_month=$(date +'%m')" >> "$GITHUB_OUTPUT" 231 232 - name: Generate Coverage Report 233 if: always() 234 run: | 235 python3 ./scripts/ci/coverage/coverage_analysis.py \ 236 -t native_sim-testplan.json \ 237 -m MAINTAINERS.yml \ 238 -c coverage/reports/merged.json \ 239 -o coverage-report-${{ steps.run_date.outputs.run_date_short }} \ 240 -f all 241 cp coverage-report-* coverage/reports/ 242 243 - name: Upload Merged Coverage Results and Report 244 if: always() 245 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 246 with: 247 name: Coverage Data and report 248 path: | 249 coverage/reports/merged.json 250 coverage/reports/merged.xml 251 coverage/reports/coverage-report-${{ steps.run_date.outputs.run_date_short }}.json 252 coverage/reports/coverage-report-${{ steps.run_date.outputs.run_date_short }}.xlsx 253 254 - name: Upload test coverage to Codecov 255 if: always() 256 uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 257 with: 258 env_vars: OS,PYTHON 259 fail_ci_if_error: false 260 verbose: true 261 token: ${{ secrets.CODECOV_TOKEN }} 262 files: coverage/reports/merged.xml 263 flags: unittests-coverage 264 265 - name: Upload Doxygen coverage to Codecov 266 if: always() 267 uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 268 with: 269 env_vars: OS,PYTHON 270 fail_ci_if_error: false 271 verbose: true 272 token: ${{ secrets.CODECOV_TOKEN }} 273 files: coverage/reports/doxygen-coverage-results/new.info 274 disable_search: true 275 flags: doxygen-coverage 276