From 75809f13e39964fef6ef29bc2d5d5ac17dc7f456 Mon Sep 17 00:00:00 2001 From: David Lane <42013603+ReenigneArcher@users.noreply.github.com> Date: Sun, 7 Dec 2025 09:01:57 -0500 Subject: [PATCH] ci(linux): migrate Archlinux build to GitHub workflow (#4478) --- .github/workflows/ci-archlinux.yml | 182 +++++++++++++++++++++++++++++ .github/workflows/ci-homebrew.yml | 3 +- .github/workflows/ci-windows.yml | 4 +- .github/workflows/ci.yml | 15 ++- DOCKER_README.md | 2 - docker/archlinux.bak | 173 --------------------------- packaging/linux/Arch/PKGBUILD | 44 ++++++- tests/CMakeLists.txt | 57 ++++++++- 8 files changed, 292 insertions(+), 188 deletions(-) create mode 100644 .github/workflows/ci-archlinux.yml delete mode 100644 docker/archlinux.bak diff --git a/.github/workflows/ci-archlinux.yml b/.github/workflows/ci-archlinux.yml new file mode 100644 index 000000000..779a6ea59 --- /dev/null +++ b/.github/workflows/ci-archlinux.yml @@ -0,0 +1,182 @@ +--- +name: CI-Archlinux +permissions: + contents: read + +on: + workflow_call: + inputs: + release_commit: + required: true + type: string + release_version: + required: true + type: string + +jobs: + build_archlinux: + name: Archlinux + env: + _use_cuda: true + _run_unit_tests: true + _support_headless_testing: true + BRANCH: ${{ github.head_ref || github.ref_name }} + BUILD_VERSION: ${{ inputs.release_version }} + CLONE_URL: ${{ github.event.repository.clone_url }} + COMMIT: ${{ inputs.release_commit }} + runs-on: ubuntu-latest + container: + image: archlinux/archlinux:base-devel + options: --cpus 4 --memory 8g + steps: + + - name: Update keyring + shell: bash + run: | + # Update keyring to avoid signature errors, and update system + pacman -Syy --disable-download-timeout --needed --noconfirm \ + archlinux-keyring + pacman -Syu --disable-download-timeout --noconfirm + pacman -Scc --noconfirm + + - name: Setup builder user + shell: bash + run: | + # arch prevents running makepkg as root + useradd -m builder + echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + + - name: Patch build flags + shell: bash + run: | + # shellcheck disable=SC2016 + sed -i 's,#MAKEFLAGS="-j2",MAKEFLAGS="-j$(nproc)",g' /etc/makepkg.conf + + - name: Install dependencies + shell: bash + run: | + pacman -Syu --disable-download-timeout --needed --noconfirm \ + base-devel \ + cmake \ + cuda \ + git \ + namcap \ + xorg-server-xvfb + pacman -Scc --noconfirm + + - name: Checkout + uses: actions/checkout@v6 + + - name: Fix workspace permissions + shell: bash + run: | + # Give builder user ownership of the workspace + chown -R builder:builder "${GITHUB_WORKSPACE}" + + - name: Configure PKGBUILD + shell: bash + run: | + # Calculate sub_version + sub_version="" + if [[ "${BRANCH}" != "master" ]]; then + sub_version=".r${COMMIT}" + fi + + # Configure PKGBUILD file (as root) + mkdir -p build + cd build + cmake \ + -DSUNSHINE_CONFIGURE_ONLY=ON \ + -DSUNSHINE_CONFIGURE_PKGBUILD=ON \ + -DSUNSHINE_SUB_VERSION="${sub_version}" \ + .. + + # Make sure builder can read from build directory + chmod -R a+rX "${GITHUB_WORKSPACE}/build" + + - name: Prepare PKGBUILD Package + shell: bash + run: | + # Create pkg directory and move files (as root) + mkdir -p pkg + mv build/PKGBUILD pkg/ + mv build/sunshine.install pkg/ + + # Change ownership to builder + chown -R builder:builder pkg + + # Run makepkg as builder user + cd pkg + sudo -u builder makepkg --printsrcinfo | tee .SRCINFO + + # create a PKGBUILD archive + cd .. + tar -czf sunshine.pkg.tar.gz -C pkg . + + - name: Build PKGBUILD + env: + DISPLAY: :1 + id: build + shell: bash + working-directory: pkg + run: | + # Add problem matcher + echo "::add-matcher::.github/matchers/gcc.json" + + source /etc/profile # ensure cuda is in the PATH + + # Run Xvfb for headless testing + Xvfb "${DISPLAY}" -screen 0 1024x768x24 & + + # Check PKGBUILD + sudo -u builder namcap -i PKGBUILD + + # Export PKGBUILD options so they're available to makepkg + export _use_cuda="${_use_cuda}" + export _run_unit_tests="${_run_unit_tests}" + export _support_headless_testing="${_support_headless_testing}" + + # Build the package as builder user (pass through environment variables) + sudo -u builder env \ + _use_cuda="${_use_cuda}" \ + _run_unit_tests="${_run_unit_tests}" \ + _support_headless_testing="${_support_headless_testing}" \ + makepkg -si --noconfirm + + # Remove debug package + rm -f sunshine-debug*.pkg.tar.zst + + # Remove problem matcher + echo "::remove-matcher owner=gcc::" + + - name: Upload coverage artifact + if: >- + always() && + (steps.build.outcome == 'success' || steps.build.outcome == 'failure') + uses: actions/upload-artifact@v5 + with: + name: coverage-Archlinux + path: | + pkg/src/build/coverage.xml + pkg/src/build/tests/test_results.xml + if-no-files-found: error + + - name: Copy Artifacts + shell: bash + run: | + # create artifacts directory + mkdir -p artifacts + + # Copy built packages to artifacts + cp pkg/sunshine*.pkg.tar.zst artifacts/ + cp sunshine.pkg.tar.gz artifacts/ + + # List artifacts + ls -la artifacts/ + + - name: Upload Artifacts + uses: actions/upload-artifact@v5 + with: + name: build-Archlinux + path: artifacts/ + if-no-files-found: error diff --git a/.github/workflows/ci-homebrew.yml b/.github/workflows/ci-homebrew.yml index d8b1d1e8d..f00b9ad79 100644 --- a/.github/workflows/ci-homebrew.yml +++ b/.github/workflows/ci-homebrew.yml @@ -156,8 +156,7 @@ jobs: if: >- always() && matrix.release != true && - (steps.test.outcome == 'success' || steps.test.outcome == 'failure') && - startsWith(github.repository, 'LizardByte/') + (steps.test.outcome == 'success' || steps.test.outcome == 'failure') uses: actions/upload-artifact@v5 with: name: coverage-Homebrew-${{ matrix.os_name }}-${{ matrix.os_version }} diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index ce93c3ecc..2aa005865 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -191,7 +191,9 @@ jobs: - name: Generate gcov report id: test_report # any except canceled or skipped - if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure') + if: >- + always() && + (steps.test.outcome == 'success' || steps.test.outcome == 'failure') shell: msys2 {0} working-directory: build run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee665f03f..a0e59fcbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,6 +99,14 @@ jobs: release_commit: ${{ needs.release-setup.outputs.release_commit }} release_version: ${{ needs.release-setup.outputs.release_version }} + build-archlinux: + name: Archlinux + needs: release-setup + uses: ./.github/workflows/ci-archlinux.yml + with: + release_commit: ${{ needs.release-setup.outputs.release_commit }} + release_version: ${{ needs.release-setup.outputs.release_version }} + build-linux-copr: name: Linux Copr if: github.event_name != 'push' # releases are handled directly in ci-copr.yml @@ -143,6 +151,7 @@ jobs: needs: - build-freebsd - build-linux + - build-archlinux - build-linux-flatpak - build-homebrew - build-windows @@ -160,6 +169,9 @@ jobs: - name: Linux-AppImage coverage: true pr: true + - name: Archlinux + coverage: true + pr: true - name: Homebrew-macos-14 coverage: false pr: true @@ -227,11 +239,12 @@ jobs: startsWith(github.repository, 'LizardByte/') needs: - release-setup + - build-archlinux - build-docker - build-freebsd + - build-homebrew - build-linux - build-linux-flatpak - - build-homebrew - build-windows runs-on: ubuntu-latest steps: diff --git a/DOCKER_README.md b/DOCKER_README.md index cbe977a39..c5298035b 100644 --- a/DOCKER_README.md +++ b/DOCKER_README.md @@ -24,7 +24,6 @@ ENTRYPOINT steam && sunshine ### SUNSHINE_OS Sunshine images are available with the following tag suffixes, based on their respective base images. -- `archlinux` - `debian-bookworm` - `ubuntu-22.04` - `ubuntu-24.04` @@ -153,7 +152,6 @@ The architectures supported by these images are shown in the table below. | tag suffix | amd64/x86_64 | arm64/aarch64 | |-----------------|--------------|---------------| -| archlinux | ✅ | ❌ | | debian-bookworm | ✅ | ✅ | | ubuntu-22.04 | ✅ | ✅ | | ubuntu-24.04 | ✅ | ✅ | diff --git a/docker/archlinux.bak b/docker/archlinux.bak deleted file mode 100644 index 6d23160c2..000000000 --- a/docker/archlinux.bak +++ /dev/null @@ -1,173 +0,0 @@ -# syntax=docker/dockerfile:1 -# artifacts: true -# platforms: linux/amd64 -# archlinux does not have an arm64 base image -# no-cache-filters: artifacts,sunshine -ARG BASE=archlinux/archlinux -ARG TAG=base-devel -FROM ${BASE}:${TAG} AS sunshine-base - -# Update keyring to avoid signature errors, and update system -RUN <<_DEPS -#!/bin/bash -set -e -pacman -Syy --disable-download-timeout --needed --noconfirm \ - archlinux-keyring -pacman -Syu --disable-download-timeout --noconfirm -pacman -Scc --noconfirm -_DEPS - -FROM sunshine-base AS sunshine-deps - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -# Install dependencies first - this layer will be cached -RUN <<_SETUP -#!/bin/bash -set -e - -# Setup builder user, arch prevents running makepkg as root -useradd -m builder -echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers - -# patch the build flags -# shellcheck disable=SC2016 -sed -i 's,#MAKEFLAGS="-j2",MAKEFLAGS="-j$(nproc)",g' /etc/makepkg.conf - -# install dependencies -pacman -Syu --disable-download-timeout --needed --noconfirm \ - base-devel \ - cmake \ - cuda \ - git \ - namcap \ - xorg-server-xvfb -pacman -Scc --noconfirm -_SETUP - -FROM sunshine-deps AS sunshine-build - -ARG BRANCH -ARG BUILD_VERSION -ARG COMMIT -ARG CLONE_URL -# note: BUILD_VERSION may be blank - -ENV BRANCH=${BRANCH} -ENV BUILD_VERSION=${BUILD_VERSION} -ENV COMMIT=${COMMIT} -ENV CLONE_URL=${CLONE_URL} - -# PKGBUILD options -ENV _use_cuda=true -ENV _run_unit_tests=true -ENV _support_headless_testing=true - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -# Setup builder user -USER builder - -# copy repository -WORKDIR /build/sunshine/ -COPY --link .. . - -# setup build directory -WORKDIR /build/sunshine/build - -# configure PKGBUILD file -RUN <<_MAKE -#!/bin/bash -set -e - -sub_version="" -if [[ "${BRANCH}" != "master" ]]; then - sub_version=".r${COMMIT}" -fi - -cmake \ - -DSUNSHINE_CONFIGURE_ONLY=ON \ - -DSUNSHINE_CONFIGURE_PKGBUILD=ON \ - -DSUNSHINE_SUB_VERSION="${sub_version}" \ - /build/sunshine -_MAKE - -WORKDIR /build/sunshine/pkg -RUN <<_PACKAGE -mv /build/sunshine/build/PKGBUILD . -mv /build/sunshine/build/sunshine.install . -makepkg --printsrcinfo > .SRCINFO -_PACKAGE - -# create a PKGBUILD archive -USER root -RUN <<_REPO -#!/bin/bash -set -e -tar -czf /build/sunshine/sunshine.pkg.tar.gz . -_REPO - -# namcap and build PKGBUILD file -USER builder -RUN <<_PKGBUILD -#!/bin/bash -set -e -# shellcheck source=/dev/null -source /etc/profile # ensure cuda is in the PATH -export DISPLAY=:1 -Xvfb ${DISPLAY} -screen 0 1024x768x24 & -namcap -i PKGBUILD -makepkg -si --noconfirm -rm -f /build/sunshine/pkg/sunshine-debug*.pkg.tar.zst -ls -a -_PKGBUILD - -FROM sunshine-base AS sunshine - -COPY --link --from=sunshine-build /build/sunshine/pkg/sunshine*.pkg.tar.zst /sunshine.pkg.tar.zst - -# artifacts to be extracted in CI -COPY --link --from=sunshine-build /build/sunshine/pkg/sunshine*.pkg.tar.zst /artifacts/sunshine.pkg.tar.zst -COPY --link --from=sunshine-build /build/sunshine/sunshine.pkg.tar.gz /artifacts/sunshine.pkg.tar.gz - -# install sunshine -RUN <<_INSTALL_SUNSHINE -#!/bin/bash -set -e -pacman -U --disable-download-timeout --needed --noconfirm \ - /sunshine.pkg.tar.zst -pacman -Scc --noconfirm -_INSTALL_SUNSHINE - -# network setup -EXPOSE 47984-47990/tcp -EXPOSE 48010 -EXPOSE 47998-48000/udp - -# setup user -ARG PGID=1000 -ENV PGID=${PGID} -ARG PUID=1000 -ENV PUID=${PUID} -ENV TZ="UTC" -ARG UNAME=lizard -ENV UNAME=${UNAME} - -ENV HOME=/home/$UNAME - -# setup user -RUN <<_SETUP_USER -#!/bin/bash -set -e -groupadd -f -g "${PGID}" "${UNAME}" -useradd -lm -d ${HOME} -s /bin/bash -g "${PGID}" -u "${PUID}" "${UNAME}" -mkdir -p ${HOME}/.config/sunshine -ln -s ${HOME}/.config/sunshine /config -chown -R ${UNAME} ${HOME} -_SETUP_USER - -USER ${UNAME} -WORKDIR ${HOME} - -# entrypoint -ENTRYPOINT ["/usr/bin/sunshine"] diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index f1ac59837..504670fd7 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -2,7 +2,7 @@ # Reference: https://wiki.archlinux.org/title/PKGBUILD ## options -: "${_run_unit_tests:=false}" # if set to true; unit tests will be executed post build; useful in CI +: "${_run_unit_tests:=false}" # if set to true; unit tests will be executed post build; useful in CI : "${_support_headless_testing:=false}" : "${_use_cuda:=detect}" # nvenc @@ -55,6 +55,10 @@ makedepends=( 'npm' ) +checkdepends=( + 'gcovr' +) + optdepends=( 'libva-mesa-driver: AMD GPU encoding support' ) @@ -160,16 +164,46 @@ build() { } check() { - cd "${srcdir}/build" - ./sunshine --version - if [[ "${_run_unit_tests::1}" == "t" ]]; then export CC="gcc-${_gcc_version}" export CXX="g++-${_gcc_version}" cd "${srcdir}/build/tests" - ./test_sunshine --gtest_color=yes + ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml + + # Generate coverage report + # Run gcovr from the build directory (where all .gcda/.gcno files are) + # This matches the pattern used in ci-linux.yml + cd "${srcdir}/build" + + # Dynamically find the gcov executable from gcc's library directory + # This ensures we use the same gcov version as the compiler + local gcov_path + gcov_path=$(find /usr/lib/gcc/x86_64-pc-linux-gnu/${_gcc_version}.*/ -name gcov -type f 2>/dev/null | head -n 1) + + if [ -z "$gcov_path" ]; then + # Fallback to standard gcov if not found + gcov_path="gcov" + fi + + echo "Using gcov at: $gcov_path" + + # Use the actual relative path to the source directory + # From ${srcdir}/build, the source is at ../${pkgname}/src + gcovr --gcov-executable "$gcov_path" . -r "../${pkgname}/src" \ + --exclude-noncode-lines \ + --exclude-throw-branches \ + --exclude-unreachable-branches \ + --verbose \ + --xml-pretty \ + -o coverage.xml + + # Post-process the coverage XML to strip the absolute path and show only 'src' + sed -i "s|${srcdir}/${pkgname}/src|src|g" coverage.xml fi + + cd "${srcdir}/build" + ./sunshine --version } package() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5a4ecd7f8..9a570fd3e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,45 @@ include_directories("${GTEST_SOURCE_DIR}/googletest/include" "${GTEST_SOURCE_DIR set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage -ggdb -O0") set(CMAKE_C_FLAGS "-fprofile-arcs -ftest-coverage -ggdb -O0") +# Find the correct libgcov library path matching the gcc compiler version +# This ensures the test executable links against the same libgcov version used during compilation +if(UNIX AND NOT APPLE) + # Get the gcc compiler version + execute_process( + COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Extract major version + string(REGEX MATCH "^[0-9]+" GCC_MAJOR_VERSION "${GCC_VERSION}") + + # Search for the gcc library directory matching this version + file(GLOB GCC_LIB_DIRS "/usr/lib/gcc/*/*${GCC_MAJOR_VERSION}.*") + + if(GCC_LIB_DIRS) + list(GET GCC_LIB_DIRS 0 GCC_LIB_DIR) + message(STATUS "Found GCC library directory: ${GCC_LIB_DIR}") + + # Look for libgcov.a in the gcc library directory + find_library(LIBGCOV_LIBRARY + NAMES gcov + PATHS ${GCC_LIB_DIR} + NO_DEFAULT_PATH + ) + + if(LIBGCOV_LIBRARY) + message(STATUS "Found libgcov: ${LIBGCOV_LIBRARY}") + # Store this to link against later + set(GCOV_LINK_LIBRARY ${LIBGCOV_LIBRARY}) + else() + message(WARNING "Could not find libgcov in ${GCC_LIB_DIR}") + endif() + else() + message(WARNING "Could not find GCC library directory for version ${GCC_VERSION}") + endif() +endif() + # if windows if (WIN32) # For Windows: Prevent overriding the parent project's compiler/linker settings @@ -102,10 +141,20 @@ endforeach() add_dependencies(${PROJECT_NAME} sync_locale_files) set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23) -target_link_libraries(${PROJECT_NAME} - ${SUNSHINE_EXTERNAL_LIBRARIES} - gtest - ${PLATFORM_LIBRARIES}) + +# Build the list of libraries to link +set(TEST_LINK_LIBRARIES + ${SUNSHINE_EXTERNAL_LIBRARIES} + gtest + ${PLATFORM_LIBRARIES} +) + +# Add the specific libgcov library if found +if(GCOV_LINK_LIBRARY) + list(APPEND TEST_LINK_LIBRARIES ${GCOV_LINK_LIBRARY}) +endif() + +target_link_libraries(${PROJECT_NAME} ${TEST_LINK_LIBRARIES}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${SUNSHINE_DEFINITIONS} ${TEST_DEFINITIONS}) target_compile_options(${PROJECT_NAME} PRIVATE $<$:${SUNSHINE_COMPILE_OPTIONS}>;$<$:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301 target_link_options(${PROJECT_NAME} PRIVATE)