ci(linux): migrate Archlinux build to GitHub workflow (#4478)

This commit is contained in:
David Lane 2025-12-07 09:01:57 -05:00 committed by GitHub
commit 75809f13e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 292 additions and 188 deletions

182
.github/workflows/ci-archlinux.yml vendored Normal file
View file

@ -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

View file

@ -156,8 +156,7 @@ jobs:
if: >- if: >-
always() && always() &&
matrix.release != true && matrix.release != true &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
startsWith(github.repository, 'LizardByte/')
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v5
with: with:
name: coverage-Homebrew-${{ matrix.os_name }}-${{ matrix.os_version }} name: coverage-Homebrew-${{ matrix.os_name }}-${{ matrix.os_version }}

View file

@ -191,7 +191,9 @@ jobs:
- name: Generate gcov report - name: Generate gcov report
id: test_report id: test_report
# any except canceled or skipped # 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} shell: msys2 {0}
working-directory: build working-directory: build
run: | run: |

View file

@ -99,6 +99,14 @@ jobs:
release_commit: ${{ needs.release-setup.outputs.release_commit }} release_commit: ${{ needs.release-setup.outputs.release_commit }}
release_version: ${{ needs.release-setup.outputs.release_version }} 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: build-linux-copr:
name: Linux Copr name: Linux Copr
if: github.event_name != 'push' # releases are handled directly in ci-copr.yml if: github.event_name != 'push' # releases are handled directly in ci-copr.yml
@ -143,6 +151,7 @@ jobs:
needs: needs:
- build-freebsd - build-freebsd
- build-linux - build-linux
- build-archlinux
- build-linux-flatpak - build-linux-flatpak
- build-homebrew - build-homebrew
- build-windows - build-windows
@ -160,6 +169,9 @@ jobs:
- name: Linux-AppImage - name: Linux-AppImage
coverage: true coverage: true
pr: true pr: true
- name: Archlinux
coverage: true
pr: true
- name: Homebrew-macos-14 - name: Homebrew-macos-14
coverage: false coverage: false
pr: true pr: true
@ -227,11 +239,12 @@ jobs:
startsWith(github.repository, 'LizardByte/') startsWith(github.repository, 'LizardByte/')
needs: needs:
- release-setup - release-setup
- build-archlinux
- build-docker - build-docker
- build-freebsd - build-freebsd
- build-homebrew
- build-linux - build-linux
- build-linux-flatpak - build-linux-flatpak
- build-homebrew
- build-windows - build-windows
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View file

@ -24,7 +24,6 @@ ENTRYPOINT steam && sunshine
### SUNSHINE_OS ### SUNSHINE_OS
Sunshine images are available with the following tag suffixes, based on their respective base images. Sunshine images are available with the following tag suffixes, based on their respective base images.
- `archlinux`
- `debian-bookworm` - `debian-bookworm`
- `ubuntu-22.04` - `ubuntu-22.04`
- `ubuntu-24.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 | | tag suffix | amd64/x86_64 | arm64/aarch64 |
|-----------------|--------------|---------------| |-----------------|--------------|---------------|
| archlinux | ✅ | ❌ |
| debian-bookworm | ✅ | ✅ | | debian-bookworm | ✅ | ✅ |
| ubuntu-22.04 | ✅ | ✅ | | ubuntu-22.04 | ✅ | ✅ |
| ubuntu-24.04 | ✅ | ✅ | | ubuntu-24.04 | ✅ | ✅ |

View file

@ -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"]

View file

@ -55,6 +55,10 @@ makedepends=(
'npm' 'npm'
) )
checkdepends=(
'gcovr'
)
optdepends=( optdepends=(
'libva-mesa-driver: AMD GPU encoding support' 'libva-mesa-driver: AMD GPU encoding support'
) )
@ -160,16 +164,46 @@ build() {
} }
check() { check() {
cd "${srcdir}/build"
./sunshine --version
if [[ "${_run_unit_tests::1}" == "t" ]]; then if [[ "${_run_unit_tests::1}" == "t" ]]; then
export CC="gcc-${_gcc_version}" export CC="gcc-${_gcc_version}"
export CXX="g++-${_gcc_version}" export CXX="g++-${_gcc_version}"
cd "${srcdir}/build/tests" 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 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() { package() {

View file

@ -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_CXX_FLAGS "-fprofile-arcs -ftest-coverage -ggdb -O0")
set(CMAKE_C_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 windows
if (WIN32) if (WIN32)
# For Windows: Prevent overriding the parent project's compiler/linker settings # For Windows: Prevent overriding the parent project's compiler/linker settings
@ -102,10 +141,20 @@ endforeach()
add_dependencies(${PROJECT_NAME} sync_locale_files) add_dependencies(${PROJECT_NAME} sync_locale_files)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23) set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23)
target_link_libraries(${PROJECT_NAME}
# Build the list of libraries to link
set(TEST_LINK_LIBRARIES
${SUNSHINE_EXTERNAL_LIBRARIES} ${SUNSHINE_EXTERNAL_LIBRARIES}
gtest gtest
${PLATFORM_LIBRARIES}) ${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_definitions(${PROJECT_NAME} PUBLIC ${SUNSHINE_DEFINITIONS} ${TEST_DEFINITIONS})
target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301 target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301
target_link_options(${PROJECT_NAME} PRIVATE) target_link_options(${PROJECT_NAME} PRIVATE)