name: SerenityOS Template on: workflow_call: inputs: toolchain: required: true type: string os: required: true type: string arch: required: true type: string debug_options: required: false type: string default: 'NORMAL_DEBUG' coverage: required: false type: string default: 'OFF' env: # runner.workspace = /home/runner/work/serenity # github.workspace = /home/runner/work/serenity/serenity SERENITY_SOURCE_DIR: ${{ github.workspace }} SERENITY_CCACHE_DIR: ${{ github.workspace }}/.ccache TOOLCHAIN_CCACHE_DIR: ${{ github.workspace }}/Toolchain/.ccache jobs: CI: runs-on: ${{ inputs.os }} steps: # Pull requests can trail behind `master` and can cause breakage if merging before running the CI checks on an updated branch. # Luckily, GitHub creates and maintains a merge branch that is updated whenever the target or source branch is modified. By # checking this branch out, we gain a stabler `master` at the cost of reproducibility. - uses: actions/checkout@v4 if: ${{ github.event_name != 'pull_request' }} - uses: actions/checkout@v4 if: ${{ github.event_name == 'pull_request' }} with: ref: refs/pull/${{ github.event.pull_request.number }}/merge - name: Set Up Environment uses: ./.github/actions/setup with: os: 'Serenity' arch: ${{ inputs.arch }} # === PREPARE FOR BUILDING === - name: Lint run: ${{ github.workspace }}/Meta/lint-ci.sh - name: Restore Caches uses: ./.github/actions/cache-restore id: 'cache-restore' with: os: 'Serenity' arch: ${{ inputs.arch }} toolchain: ${{ inputs.toolchain }} cache_key_extra: ${{ inputs.debug_options }}-COVERAGE_${{ inputs.coverage }} serenity_ccache_path: ${{ env.SERENITY_CCACHE_DIR }} toolchain_ccache_path: ${{ env.TOOLCHAIN_CCACHE_DIR }} download_cache_path: ${{ github.workspace }}/Build/caches - name: Assign Build Parameters id: 'build-parameters' run: | if ${{ inputs.toolchain == 'Clang' }} ; then echo "build_directory=${{ github.workspace }}/Build/${{ inputs.arch }}clang" >> "$GITHUB_OUTPUT" elif ${{ inputs.toolchain == 'GNU' }} ; then echo "build_directory=${{ github.workspace }}/Build/${{ inputs.arch }}" >> "$GITHUB_OUTPUT" fi - name: Build Toolchain if: ${{ !steps.cache-restore.outputs.toolchain_prebuilt_hit }} run: | ${{ github.workspace }}/Toolchain/Build${{ inputs.toolchain }}.sh --ci env: ARCH: ${{ inputs.arch}} CCACHE_DIR: ${{ env.TOOLCHAIN_CCACHE_DIR }} - name: Build AArch64 Qemu if: ${{ inputs.arch == 'aarch64' && !steps.cache-restore.outputs.qemu_cache_hit }} run: ${{ github.workspace }}/Toolchain/BuildQemu.sh env: CCACHE_DIR: ${{ env.TOOLCHAIN_CCACHE_DIR }} - name: Create Build Environment if: ${{ inputs.debug_options == 'ALL_DEBUG' }} # Build the entire project with all available debug options turned on, to prevent code rot. # However, it is unwieldy and slow to run tests with them enabled, so we will build twice. run: | cmake -S Meta/CMake/Superbuild -B Build/superbuild -GNinja \ -DSERENITY_ARCH=${{ inputs.arch }} \ -DSERENITY_TOOLCHAIN=${{ inputs.toolchain }} \ -DBUILD_LAGOM=ON \ -DCMAKE_C_COMPILER=gcc-13 \ -DCMAKE_CXX_COMPILER=g++-13 \ -DENABLE_ALL_DEBUG_FACILITIES=ON \ -DENABLE_PCI_IDS_DOWNLOAD=OFF \ -DENABLE_USB_IDS_DOWNLOAD=OFF env: CCACHE_DIR: ${{ env.SERENITY_CCACHE_DIR }} - name: Create Build Environment if: ${{ inputs.debug_options == 'NORMAL_DEBUG' }} working-directory: ${{ github.workspace }} # Note that we do not set BUILD_LAGOM for the normal debug build # We build and run the Lagom tests in a separate job, and sanitizer builds take a good while longer than non-sanitized. run: | cmake -S Meta/CMake/Superbuild -B Build/superbuild -GNinja \ -DSERENITY_ARCH=${{ inputs.arch }} \ -DSERENITY_TOOLCHAIN=${{ inputs.toolchain }} \ -DCMAKE_C_COMPILER=gcc-13 \ -DCMAKE_CXX_COMPILER=g++-13 \ -DENABLE_UNDEFINED_SANITIZER=ON \ -DUNDEFINED_BEHAVIOR_IS_FATAL=ON \ -DENABLE_USERSPACE_COVERAGE_COLLECTION=${{ inputs.coverage }} \ -DDUMP_REGIONS_ON_CRASH=ON \ -DENABLE_PCI_IDS_DOWNLOAD=OFF \ -DENABLE_USB_IDS_DOWNLOAD=OFF env: CCACHE_DIR: ${{ env.SERENITY_CCACHE_DIR }} # === BUILD === - name: Build Serenity and Tests working-directory: ${{ github.workspace }}/Build/superbuild run: cmake --build . env: CCACHE_DIR: ${{ env.SERENITY_CCACHE_DIR }} - name: Save Caches uses: ./.github/actions/cache-save with: arch: ${{ inputs.arch }} qemu_cache_primary_key: ${{ steps.cache-restore.outputs.qemu_cache_primary_key }} qemu_cache_hit: ${{ steps.cache-restore.outputs.qemu_cache_hit }} serenity_ccache_path: ${{ env.SERENITY_CCACHE_DIR }} serenity_ccache_primary_key: ${{ steps.cache-restore.outputs.serenity_ccache_primary_key }} toolchain_ccache_path: ${{ env.TOOLCHAIN_CCACHE_DIR }} toolchain_ccache_primary_key: ${{ steps.cache-restore.outputs.toolchain_ccache_primary_key }} toolchain_prebuilt_path: ${{ steps.cache-restore.outputs.toolchain_prebuilt_path }} toolchain_prebuilt_primary_key: ${{ steps.cache-restore.outputs.toolchain_prebuilt_primary_key }} toolchain_prebuilt_hit: ${{ steps.cache-restore.outputs.toolchain_prebuilt_hit }} # === TEST === - name: Create Serenity Rootfs if: ${{ inputs.debug_options == 'NORMAL_DEBUG' }} working-directory: ${{ steps.build-parameters.outputs.build_directory }} run: ninja install && ninja qemu-image - name: Run On-Target Tests if: ${{ inputs.debug_options == 'NORMAL_DEBUG' && inputs.arch != 'aarch64' }} working-directory: ${{ steps.build-parameters.outputs.build_directory }} env: SERENITY_QEMU_CPU: "max,vmx=off" SERENITY_KERNEL_CMDLINE: "graphics_subsystem_mode=off panic=shutdown system_mode=self-test" SERENITY_RUN: "ci" run: | echo "::group::ninja run # Qemu output" ninja run echo "::endgroup::" echo "::group::Verify Output File" mkdir fsmount sudo mount -t ext2 -o loop,rw _disk_image fsmount echo "Results: " sudo cat fsmount/home/anon/test-results.log if ! sudo grep -q "Failed: 0" fsmount/home/anon/test-results.log then echo "::error:: :^( Tests failed, failing job" exit 1 fi echo "::endgroup::" timeout-minutes: 60 - name: Print Target Logs # Extremely useful if Serenity hangs trying to run one of the tests if: ${{ !cancelled() && inputs.debug_options == 'NORMAL_DEBUG'}} working-directory: ${{ steps.build-parameters.outputs.build_directory }} run: '[ ! -e debug.log ] || cat debug.log' # === COVERAGE === - name: Aggregate Coverage Results if: ${{ inputs.coverage == 'ON' }} working-directory: ${{ github.workspace }} run: ./Meta/analyze-qemu-coverage.sh env: SERENITY_TOOLCHAIN: ${{ matrix.toolchain }} SERENITY_ARCH: ${{ matrix.arch }} # FIXME: Deploy the static html pages somewhere # FIXME: Alter script to also (instead?) produce a raw coverage.txt file for ingestion into sonar cloud # Note: tmp_profile_data/Coverage.profdata has the entire combined profile data, but creating the raw txt requires # all of the instrumented binaries and the profdata file. - name: Upload Coverage Results if: ${{ inputs.coverage == 'ON' }} uses: actions/upload-artifact@v4 with: name: serenity-coverage path: ${{ steps.build-parameters.outputs.build_directory }}/reports retention-days: 90