Skip to content

CI

CI #45

Workflow file for this run

---
name: CI
on:
pull_request:
branches: [master, nightly]
types: [opened, synchronize, reopened]
push:
branches: [master, nightly, patch-13]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
github_env:
name: GitHub Env Debug
runs-on: ubuntu-latest
steps:
- name: Dump github context
run: echo "$GITHUB_CONTEXT"
shell: bash
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
check_changelog:
name: Check Changelog
runs-on: ubuntu-latest
steps:
- name: Checkout
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }}
uses: actions/checkout@v4
- name: Verify Changelog
id: verify_changelog
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }}
# base_ref for pull request check, ref for push
uses: LizardByte/.github/actions/verify_changelog@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
outputs:
next_version: ${{ steps.verify_changelog.outputs.changelog_parser_version }}
next_version_bare: ${{ steps.verify_changelog.outputs.changelog_parser_version_bare }}
last_version: ${{ steps.verify_changelog.outputs.latest_release_tag_name }}
release_body: ${{ steps.verify_changelog.outputs.changelog_parser_description }}
# todo - remove this job once versioning is fully automated by cmake
check_versions:
name: Check Versions
runs-on: ubuntu-latest
needs: check_changelog
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }}
# base_ref for pull request check, ref for push
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check CMakeLists.txt Version
run: |
version=$(grep -o -E '^project\(Sunshine VERSION [0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt | \
grep -o -E '[0-9]+\.[0-9]+\.[0-9]+')
echo "cmakelists_version=${version}" >> $GITHUB_ENV
- name: Compare CMakeList.txt Version
if: ${{ env.cmakelists_version != needs.check_changelog.outputs.next_version_bare }}
run: |
echo CMakeLists version: "$cmakelists_version"
echo Changelog version: "${{ needs.check_changelog.outputs.next_version_bare }}"
echo Within 'CMakeLists.txt' change "project(Sunshine [VERSION $cmakelists_version]" to \
"project(Sunshine [VERSION ${{ needs.check_changelog.outputs.next_version_bare }}]"
exit 1
setup_release:
name: Setup Release
needs: check_changelog
runs-on: ubuntu-latest
steps:
- name: Set release details
id: release_details
env:
RELEASE_BODY: ${{ needs.check_changelog.outputs.release_body }}
run: |
# determine to create a release or not
if [[ $GITHUB_EVENT_NAME == "push" ]]; then
RELEASE=true
else
RELEASE=false
fi
# set the release tag
COMMIT=${{ github.sha }}
if [[ $GITHUB_REF == refs/heads/master ]]; then
TAG="${{ needs.check_changelog.outputs.next_version }}"
RELEASE_NAME="${{ needs.check_changelog.outputs.next_version }}"
RELEASE_BODY="$RELEASE_BODY"
PRE_RELEASE="false"
elif [[ $GITHUB_REF == refs/heads/nightly ]]; then
TAG="nightly-dev"
RELEASE_NAME="nightly"
RELEASE_BODY="automated nightly release - $(date -u +'%Y-%m-%dT%H:%M:%SZ') - ${COMMIT}"
PRE_RELEASE="true"
fi
echo "create_release=${RELEASE}" >> $GITHUB_OUTPUT
echo "release_tag=${TAG}" >> $GITHUB_OUTPUT
echo "release_commit=${COMMIT}" >> $GITHUB_OUTPUT
echo "release_name=${RELEASE_NAME}" >> $GITHUB_OUTPUT
echo "pre_release=${PRE_RELEASE}" >> $GITHUB_OUTPUT
# this is stupid but works for multiline strings
echo "RELEASE_BODY<<EOF" >> $GITHUB_ENV
echo "$RELEASE_BODY" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
outputs:
create_release: ${{ steps.release_details.outputs.create_release }}
release_tag: ${{ steps.release_details.outputs.release_tag }}
release_commit: ${{ steps.release_details.outputs.release_commit }}
release_name: ${{ steps.release_details.outputs.release_name }}
release_body: ${{ env.RELEASE_BODY }}
pre_release: ${{ steps.release_details.outputs.pre_release }}
setup_flatpak_matrix:
name: Setup Flatpak Matrix
runs-on: ubuntu-latest
steps:
- name: Set release details
id: flatpak_matrix
# https://www.cynkra.com/blog/2020-12-23-dynamic-gha
run: |
# determine which architectures to build
if [[ $GITHUB_EVENT_NAME == "push" ]]; then
matrix=$((
echo '{ "arch" : ["x86_64", "aarch64"] }'
) | jq -c .)
else
matrix=$((
echo '{ "arch" : ["x86_64"] }'
) | jq -c .)
fi
echo $matrix
echo $matrix | jq .
echo "matrix=$matrix" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.flatpak_matrix.outputs.matrix }}
build_linux_flatpak:
name: Linux Flatpak
runs-on: ubuntu-22.04
needs: [setup_release, setup_flatpak_matrix]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix: ${{fromJson(needs.setup_flatpak_matrix.outputs.matrix)}}
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@v8
with:
root-reserve-mb: 10240
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Dependencies Linux Flatpak
run: |
PLATFORM_VERSION=22.08
sudo apt-get update -y
sudo apt-get install -y \
cmake \
flatpak \
qemu-user-static
sudo su $(whoami) -c "flatpak --user remote-add --if-not-exists flathub \
https://flathub.org/repo/flathub.flatpakrepo"
sudo su $(whoami) -c "flatpak --user install -y flathub \
org.flatpak.Builder \
org.freedesktop.Platform/${{ matrix.arch }}/${PLATFORM_VERSION} \
org.freedesktop.Sdk/${{ matrix.arch }}/${PLATFORM_VERSION} \
org.freedesktop.Sdk.Extension.node18/${{ matrix.arch }}/${PLATFORM_VERSION} \
org.freedesktop.Sdk.Extension.vala/${{ matrix.arch }}/${PLATFORM_VERSION} \
"
- name: Cache Flatpak build
uses: actions/cache@v3
with:
path: ./build/.flatpak-builder
key: flatpak-${{ matrix.arch }}-${{ github.sha }}
restore-keys: |
flatpak-${{ matrix.arch }}-
- name: Configure Flatpak Manifest
run: |
# variables for manifest
branch=${GITHUB_HEAD_REF}
# check the branch variable
if [ -z "$branch" ]
then
echo "This is a PUSH event"
branch=${{ github.ref_name }}
commit=${{ github.sha }}
clone_url=${{ github.event.repository.clone_url }}
else
echo "This is a PR event"
commit=${{ github.event.pull_request.head.sha }}
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
fi
echo "Branch: ${branch}"
echo "Commit: ${commit}"
echo "Clone URL: ${clone_url}"
mkdir -p build
mkdir -p artifacts
cd build
cmake -DGITHUB_CLONE_URL=${clone_url} \
-DGITHUB_BRANCH=${branch} \
-DGITHUB_COMMIT=${commit} \
-DSUNSHINE_CONFIGURE_FLATPAK_MAN=ON \
-DSUNSHINE_CONFIGURE_ONLY=ON \
..
- name: Build Linux Flatpak
working-directory: build
run: |
sudo su $(whoami) -c 'flatpak run org.flatpak.Builder --arch=${{ matrix.arch }} --repo=repo --force-clean \
--stop-at=cuda build-sunshine dev.lizardbyte.sunshine.yml'
cp -r .flatpak-builder copy-of-flatpak-builder
sudo su $(whoami) -c 'flatpak run org.flatpak.Builder --arch=${{ matrix.arch }} --repo=repo --force-clean \
build-sunshine dev.lizardbyte.sunshine.yml'
rm -rf .flatpak-builder
mv copy-of-flatpak-builder .flatpak-builder
sudo su $(whoami) -c 'flatpak build-bundle --arch=${{ matrix.arch }} ./repo \
../artifacts/sunshine_${{ matrix.arch }}.flatpak dev.lizardbyte.sunshine'
sudo su $(whoami) -c 'flatpak build-bundle --runtime --arch=${{ matrix.arch }} ./repo \
../artifacts/sunshine_debug_${{ matrix.arch }}.flatpak dev.lizardbyte.sunshine.Debug'
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: sunshine-linux-flatpak-${{ matrix.arch }}
path: artifacts/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' }}
uses: ncipollo/release-action@v1
with:
name: ${{ needs.setup_release.outputs.release_name }}
tag: ${{ needs.setup_release.outputs.release_tag }}
commit: ${{ needs.setup_release.outputs.release_commit }}
artifacts: "*artifacts/*"
token: ${{ secrets.GH_BOT_TOKEN }}
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
build_linux:
name: Linux ${{ matrix.type }}
runs-on: ubuntu-${{ matrix.dist }}
needs: [check_changelog, setup_release]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
include: # package these differently
- type: AppImage
EXTRA_ARGS: '-DSUNSHINE_BUILD_APPIMAGE=ON'
dist: 20.04
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@v8
with:
root-reserve-mb: 30720
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install wget
run: |
sudo apt-get update -y
sudo apt-get install -y \
wget
- name: Install CUDA
env:
CUDA_VERSION: 11.8.0
CUDA_BUILD: 520.61.05
timeout-minutes: 4
run: |
url_base="https://developer.download.nvidia.com/compute/cuda/${CUDA_VERSION}/local_installers"
url="${url_base}/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux.run"
sudo wget -q -O /root/cuda.run ${url}
sudo chmod a+x /root/cuda.run
sudo /root/cuda.run --silent --toolkit --toolkitpath=/usr/local/cuda --no-opengl-libs --no-man-page --no-drm
sudo rm /root/cuda.run
- name: Setup Dependencies Linux
timeout-minutes: 5
run: |
# allow newer gcc
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt-get install -y \
build-essential \
cmake \
gcc-10 \
g++-10 \
libayatana-appindicator3-dev \
libavdevice-dev \
libboost-filesystem-dev \
libboost-locale-dev \
libboost-log-dev \
libboost-program-options-dev \
libcap-dev \
libcurl4-openssl-dev \
libdrm-dev \
libevdev-dev \
libminiupnpc-dev \
libmfx-dev \
libnotify-dev \
libnuma-dev \
libopus-dev \
libpulse-dev \
libssl-dev \
libva-dev \
libvdpau-dev \
libwayland-dev \
libx11-dev \
libxcb-shm0-dev \
libxcb-xfixes0-dev \
libxcb1-dev \
libxfixes-dev \
libxrandr-dev \
libxtst-dev \
python3
# clean apt cache
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
# Update gcc alias
# https://stackoverflow.com/a/70653945/11214013
sudo update-alternatives --install \
/usr/bin/gcc gcc /usr/bin/gcc-10 100 \
--slave /usr/bin/g++ g++ /usr/bin/g++-10 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-10 \
--slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-10 \
--slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-10
- name: Setup python
id: python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build Linux
env:
BRANCH: ${{ github.head_ref || github.ref_name }}
BUILD_VERSION: ${{ needs.check_changelog.outputs.next_version_bare }}
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
timeout-minutes: 5
run: |
echo "nproc: $(nproc)"
mkdir -p build
mkdir -p artifacts
cd build
cmake \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CUDA_COMPILER:PATH=/usr/local/cuda/bin/nvcc \
-DCMAKE_INSTALL_PREFIX=/usr \
-DSUNSHINE_ASSETS_DIR=share/sunshine \
-DSUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \
-DSUNSHINE_ENABLE_WAYLAND=ON \
-DSUNSHINE_ENABLE_X11=ON \
-DSUNSHINE_ENABLE_DRM=ON \
-DSUNSHINE_ENABLE_CUDA=ON \
${{ matrix.EXTRA_ARGS }} \
..
make -j $(expr $(nproc) - 1) # use all but one core
- name: Set AppImage Version
if: |
matrix.type == 'AppImage' &&
(needs.check_changelog.outputs.next_version_bare != needs.check_changelog.outputs.last_version)
run: |
version=${{ needs.check_changelog.outputs.next_version_bare }}
echo "VERSION=${version}" >> $GITHUB_ENV
- name: Package Linux - AppImage
if: ${{ matrix.type == 'AppImage' }}
working-directory: build
run: |
# install sunshine to the DESTDIR
make install DESTDIR=AppDir
# custom AppRun file
cp -f ../packaging/linux/AppImage/AppRun ./AppDir/
chmod +x ./AppDir/AppRun
# variables
DESKTOP_FILE="${DESKTOP_FILE:-sunshine.desktop}"
ICON_FILE="${ICON_FILE:-sunshine.png}"
# AppImage
# https://docs.appimage.org/packaging-guide/index.html
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
# https://github.com/linuxdeploy/linuxdeploy-plugin-gtk
sudo apt-get install libgtk-3-dev librsvg2-dev -y
wget -q https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh
chmod +x linuxdeploy-plugin-gtk.sh
export DEPLOY_GTK_VERSION=3
./linuxdeploy-x86_64.AppImage \
--appdir ./AppDir \
--plugin gtk \
--executable ./sunshine \
--icon-file "../$ICON_FILE" \
--desktop-file "./$DESKTOP_FILE" \
--output appimage
# move
mv Sunshine*.AppImage ../artifacts/sunshine.AppImage
# permissions
chmod +x ../artifacts/sunshine.AppImage
- name: Delete cuda
# free up space on the runner
run: |
sudo rm -rf /usr/local/cuda
- name: Verify AppImage
if: ${{ matrix.type == 'AppImage' }}
run: |
wget https://github.com/TheAssassin/appimagelint/releases/download/continuous/appimagelint-x86_64.AppImage
chmod +x appimagelint-x86_64.AppImage
./appimagelint-x86_64.AppImage ./artifacts/sunshine.AppImage
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: sunshine-linux-${{ matrix.type }}-${{ matrix.dist }}
path: artifacts/
- name: Install test deps
run: |
sudo apt-get update -y
sudo apt-get install -y \
doxygen \
graphviz \
python3-venv \
x11-xserver-utils \
xvfb
# clean apt cache
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
- name: Run tests
id: test
working-directory: build/tests
run: |
export DISPLAY=:1
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
./test_sunshine --gtest_color=yes
- name: Generate gcov report
# any except canceled or skipped
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
working-directory: build
run: |
${{ steps.python.outputs.python-path }} -m pip install gcovr
${{ steps.python.outputs.python-path }} -m gcovr -r .. \
--exclude '.*tests/.*' \
--exclude '.*tests/.*' \
--xml-pretty \
-o coverage.xml
- name: Upload coverage
# any except canceled or skipped
if: always() && (steps.test_report.outcome == 'success')
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
files: ./build/coverage.xml
flags: ${{ runner.os }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' }}
uses: ncipollo/release-action@v1
with:
name: ${{ needs.setup_release.outputs.release_name }}
tag: ${{ needs.setup_release.outputs.release_tag }}
commit: ${{ needs.setup_release.outputs.release_commit }}
artifacts: "*artifacts/*"
token: ${{ secrets.GH_BOT_TOKEN }}
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
build_mac_brew:
needs: [check_changelog, setup_release]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
include:
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
# while GitHub has larger macOS runners, they are not available for our repos :(
- os_version: "12"
release: true
- os_version: "13"
- os_version: "14"
name: Homebrew (macOS-${{ matrix.os_version }})
runs-on: macos-${{ matrix.os_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Dependencies Homebrew
run: |
# install dependencies using homebrew
brew install cmake
- name: Configure formula
run: |
# variables for formula
branch=${GITHUB_HEAD_REF}
# check the branch variable
if [ -z "$branch" ]
then
echo "This is a PUSH event"
clone_url=${{ github.event.repository.clone_url }}
branch="${{ github.ref_name }}"
default_branch="${{ github.event.repository.default_branch }}"
else
echo "This is a PR event"
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
branch="${{ github.event.pull_request.head.ref }}"
default_branch="${{ github.event.pull_request.head.repo.default_branch }}"
fi
echo "Branch: ${branch}"
echo "Clone URL: ${clone_url}"
mkdir build
cd build
cmake \
-DGITHUB_BRANCH="${branch}" \
-DGITHUB_CLONE_URL="${clone_url}" \
-DGITHUB_DEFAULT_BRANCH="${default_branch}" \
-DSUNSHINE_CONFIGURE_HOMEBREW=ON \
-DSUNSHINE_CONFIGURE_ONLY=ON \
..
cd ..
# copy formula to artifacts
mkdir -p homebrew
cp -f ./build/sunshine.rb ./homebrew/sunshine.rb
# testing
cat ./homebrew/sunshine.rb
- name: Upload Artifacts
if: ${{ matrix.release }}
uses: actions/upload-artifact@v4
with:
name: sunshine-homebrew
path: homebrew/
- name: Should Publish Homebrew Formula
id: homebrew_publish
run: |
PUBLISH=false
if [[ \
"${{ matrix.release }}" == "true" && \
"${{ github.repository_owner }}" == "LizardByte" && \
"${{ needs.setup_release.outputs.create_release }}" == "true" && \
"${{ github.ref }}" == "refs/heads/master" \
]]; then
PUBLISH=true
fi
echo "publish=${PUBLISH}" >> $GITHUB_OUTPUT
- name: Validate and Publish Homebrew Formula
uses: LizardByte/homebrew-release-action@v2024.409.24405
with:
formula_file: ${{ github.workspace }}/homebrew/sunshine.rb
git_email: ${{ secrets.GH_BOT_EMAIL }}
git_username: ${{ secrets.GH_BOT_NAME }}
publish: ${{ steps.homebrew_publish.outputs.publish }}
token: ${{ secrets.GH_BOT_TOKEN }}
build_mac_port:
needs: [check_changelog, setup_release]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
include:
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
# while GitHub has larger macOS runners, they are not available for our repos :(
- os_version: "12"
release: true
- os_version: "13"
- os_version: "14"
name: Macports (macOS-${{ matrix.os_version }})
runs-on: macos-${{ matrix.os_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Checkout ports
uses: actions/checkout@v4
with:
repository: macports/macports-ports
fetch-depth: 64
path: ports
- name: Checkout mpbb
uses: actions/checkout@v4
with:
repository: macports/mpbb
path: mpbb
- name: Setup Dependencies Macports
run: |
# install dependencies using homebrew
brew install cmake
- name: Setup python
id: python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Configure Portfile
run: |
# variables for Portfile
branch=${GITHUB_HEAD_REF}
# check the branch variable
if [ -z "$branch" ]
then
echo "This is a PUSH event"
commit=${{ github.sha }}
clone_url=${{ github.event.repository.clone_url }}
else
echo "This is a PR event"
commit=${{ github.event.pull_request.head.sha }}
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
fi
echo "Commit: ${commit}"
echo "Clone URL: ${clone_url}"
mkdir build
cd build
cmake \
-DGITHUB_COMMIT=${commit} \
-DGITHUB_CLONE_URL=${clone_url} \
-DSUNSHINE_CONFIGURE_PORTFILE=ON \
-DSUNSHINE_CONFIGURE_ONLY=ON \
..
cd ..
# copy Portfile to artifacts
mkdir -p artifacts
cp -f ./build/Portfile ./artifacts/
# copy Portfile to ports
mkdir -p ./ports/multimedia/Sunshine
cp -f ./build/Portfile ./ports/multimedia/Sunshine/Portfile
# testing
cat ./artifacts/Portfile
- name: Bootstrap MacPorts
run: |
. ports/.github/workflows/bootstrap.sh
# Add getopt, mpbb and the MacPorts paths to $PATH for the subsequent steps.
echo "/opt/mports/bin" >> $GITHUB_PATH
echo "${PWD}/mpbb" >> $GITHUB_PATH
echo "/opt/local/bin" >> $GITHUB_PATH
echo "/opt/local/sbin" >> $GITHUB_PATH
- name: Run port lint
run: |
port -q lint "Sunshine"
- name: Build port
env:
subportlist: ${{ steps.subportlist.outputs.subportlist }}
id: build
run: |
subport="Sunshine"
workdir="/tmp/mpbb/$subport"
mkdir -p "$workdir/logs"
echo "::group::Installing dependencies"
sudo mpbb \
--work-dir "$workdir" \
install-dependencies \
"$subport"
echo "::endgroup::"
echo "::group::Installing ${subport}"
sudo mpbb \
--work-dir "$workdir" \
install-port \
--source \
"$subport"
echo "::endgroup::"
- name: Build Logs
if: always()
run: |
logfile="/opt/local/var/macports/logs/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/main.log"
cat "$logfile"
sudo mv "${logfile}" "${logfile}.bak"
- name: Upload Artifacts
if: ${{ matrix.release }}
uses: actions/upload-artifact@v4
with:
name: sunshine-macports
path: artifacts/
- name: Fix screen capture permissions
if: ${{ matrix.os_version != 12 }} # macOS-12 is okay
# can be removed if the following is fixed in the runner image
# https://github.com/actions/runner-images/issues/9529
# https://github.com/actions/runner-images/pull/9530
run: |
# https://apple.stackexchange.com/questions/362865/macos-list-apps-authorized-for-full-disk-access
# permissions for screen capture
values="'kTCCServiceScreenCapture','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
if [[ "${{ matrix.os_version }}" == "14" ]]; then
# TCC access table in Sonoma has extra 4 columns: pid, pid_version, boot_uuid, last_reminded
values="${values},NULL,NULL,'UNUSED',${values##*,}"
fi
# system and user databases
dbPaths=(
"/Library/Application Support/com.apple.TCC/TCC.db"
"$HOME/Library/Application Support/com.apple.TCC/TCC.db"
)
sqlQuery="INSERT OR IGNORE INTO access VALUES($values);"
for dbPath in "${dbPaths[@]}"; do
echo "Column names for $dbPath"
echo "-------------------"
sudo sqlite3 "$dbPath" "PRAGMA table_info(access);"
echo "Current permissions for $dbPath"
echo "-------------------"
sudo sqlite3 "$dbPath" "SELECT * FROM access WHERE service='kTCCServiceScreenCapture';"
sudo sqlite3 "$dbPath" "$sqlQuery"
echo "Updated permissions for $dbPath"
echo "-------------------"
sudo sqlite3 "$dbPath" "SELECT * FROM access WHERE service='kTCCServiceScreenCapture';"
done
- name: Run tests
id: test
timeout-minutes: 10
run: |
sudo port test "Sunshine"
- name: Test Logs
if: always()
run: |
logfile="/opt/local/var/macports/logs/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/main.log"
cat "$logfile"
- name: Generate gcov report
# any except canceled or skipped
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
working-directory:
/opt/local/var/macports/build/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/work
run: |
base_dir=$(pwd)
build_dir=${base_dir}/build
# get the directory name that starts with Sunshine-*
dir=$(ls -d Sunshine-*)
cd ${build_dir}
${{ steps.python.outputs.python-path }} -m pip install gcovr
sudo ${{ steps.python.outputs.python-path }} -m gcovr -r ../${dir} \
--exclude '.*${dir}/tests/.*' \
--exclude '.*${dir}/third-party/.*' \
--gcov-object-directory $(pwd) \
--verbose \
--xml-pretty \
-o ${{ github.workspace }}/build/coverage.xml
- name: Upload coverage
# any except canceled or skipped
if: always() && (steps.test_report.outcome == 'success')
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: false # todo: re-enable this when action is fixed
files: ./build/coverage.xml
flags: ${{ runner.os }}-${{ matrix.os_version }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' && matrix.release }}
uses: ncipollo/release-action@v1
with:
name: ${{ needs.setup_release.outputs.release_name }}
tag: ${{ needs.setup_release.outputs.release_tag }}
commit: ${{ needs.setup_release.outputs.release_commit }}
artifacts: "*artifacts/*"
token: ${{ secrets.GH_BOT_TOKEN }}
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
build_win:
name: Windows
runs-on: windows-2019
needs: [check_changelog, setup_release]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Prepare tests
id: prepare-tests
if: false # todo: DirectX11 is not available, so even software encoder fails
run: |
# function to download and extract a zip file
function DownloadAndExtract {
param (
[string]$Uri,
[string]$OutFile
)
$maxRetries = 5
$retryCount = 0
$success = $false
while (-not $success -and $retryCount -lt $maxRetries) {
$retryCount++
Write-Host "Downloading $Uri to $OutFile, attempt $retryCount of $maxRetries"
try {
Invoke-WebRequest -Uri $Uri -OutFile $OutFile
$success = $true
} catch {
Write-Host "Attempt $retryCount of $maxRetries failed with error: $($_.Exception.Message). Retrying..."
Start-Sleep -Seconds 5
}
}
if (-not $success) {
Write-Host "Failed to download the file after $maxRetries attempts."
exit 1
}
# use .NET to get the base name of the file
$baseName = (Get-Item $OutFile).BaseName
# Extract the zip file
Expand-Archive -Path $OutFile -DestinationPath $baseName
}
# virtual display driver
DownloadAndExtract `
-Uri "https://www.amyuni.com/downloads/usbmmidd_v2.zip" `
-OutFile "usbmmidd_v2.zip"
# install
Set-Location -Path usbmmidd_v2/usbmmidd_v2
./deviceinstaller64 install usbmmidd.inf usbmmidd
# create the virtual display
./deviceinstaller64 enableidd 1
# move up a directory
Set-Location -Path ../..
# install devcon
DownloadAndExtract `
-Uri "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.zip" `
-OutFile "Devcon.Installer.zip"
Set-Location -Path Devcon.Installer
# hash needs to match OS version
# https://github.com/Drawbackz/DevCon-Installer/blob/master/devcon_sources.json
Start-Process -FilePath "./Devcon Installer.exe" -Wait -ArgumentList `
'install', `
'-hash', '54004C83EE34F6A55380528A8B29F4C400E61FBB947A19E0AB9E5A193D7D961E', `
'-addpath', `
'-update', `
'-dir', 'C:\Windows\System32'
# disable Hyper-V Video
# https://stackoverflow.com/a/59490940
C:\Windows\System32\devcon.exe disable "VMBUS\{da0a7802-e377-4aac-8e77-0558eb1073f8}"
# move up a directory
Set-Location -Path ..
# multi monitor tool
DownloadAndExtract `
-Uri "http://www.nirsoft.net/utils/multimonitortool-x64.zip" `
-OutFile "multimonitortool.zip"
# enable the virtual display
# http://www.nirsoft.net/utils/multi_monitor_tool.html
Set-Location -Path multimonitortool
# Original Hyper-V is \\.\DISPLAY1, it will recreate itself as \\.\DISPLAY6 (or something higher than 2)
# USB Mobile Monitor Virtual Display is \\.\DISPLAY2
# these don't seem to work if not using runAs
# todo: do they work if not using runAs?
Start-Process powershell -Verb runAs -ArgumentList '-Command ./MultiMonitorTool.exe /enable \\.\DISPLAY2'
Start-Process powershell -Verb runAs -ArgumentList '-Command ./MultiMonitorTool.exe /SetPrimary \\.\DISPLAY2'
# wait a few seconds
Start-Sleep -s 5
# list monitors
./MultiMonitorTool.exe /stext monitor_list.txt
# wait a few seconds
Start-Sleep -s 5
# print the monitor list
Get-Content -Path monitor_list.txt
- name: Setup Dependencies Windows
uses: msys2/setup-msys2@v2
with:
update: true
install: >-
base-devel
diffutils
doxygen
git
make
mingw-w64-x86_64-binutils
mingw-w64-x86_64-boost
mingw-w64-x86_64-cmake
mingw-w64-x86_64-curl
mingw-w64-x86_64-graphviz
mingw-w64-x86_64-miniupnpc
mingw-w64-x86_64-nlohmann-json
mingw-w64-x86_64-nodejs
mingw-w64-x86_64-nsis
mingw-w64-x86_64-onevpl
mingw-w64-x86_64-openssl
mingw-w64-x86_64-opus
mingw-w64-x86_64-toolchain
nasm
wget
yasm
- name: Setup python
# use this instead of msys2 python due to known issues using wheels, https://www.msys2.org/docs/python/
id: setup-python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Python Path
id: python-path
shell: msys2 {0}
run: |
# replace backslashes with double backslashes
python_path=$(echo "${{ steps.setup-python.outputs.python-path }}" | sed 's/\\/\\\\/g')
# step output
echo "python-path=${python_path}"
echo "python-path=${python_path}" >> $GITHUB_OUTPUT
- name: Build Windows
shell: msys2 {0}
env:
BRANCH: ${{ github.head_ref || github.ref_name }}
BUILD_VERSION: ${{ needs.check_changelog.outputs.next_version_bare }}
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
mkdir build
cd build
cmake \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DSUNSHINE_ASSETS_DIR=assets \
-DTESTS_PYTHON_EXECUTABLE='${{ steps.python-path.outputs.python-path }}' \
-DTESTS_SOFTWARE_ENCODER_UNAVAILABLE='skip' \
-G "MinGW Makefiles" \
..
mingw32-make -j$(nproc)
- name: Package Windows
shell: msys2 {0}
run: |
mkdir -p artifacts
cd build
# package
cpack -G NSIS
cpack -G ZIP
# move
mv ./cpack_artifacts/Sunshine.exe ../artifacts/sunshine-windows-installer.exe
mv ./cpack_artifacts/Sunshine.zip ../artifacts/sunshine-windows-portable.zip
- name: Run tests
id: test
shell: msys2 {0}
working-directory: build/tests
run: |
./test_sunshine.exe --gtest_color=yes
- name: Generate gcov report
# any except canceled or skipped
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
shell: msys2 {0}
working-directory: build
run: |
${{ steps.python-path.outputs.python-path }} -m pip install gcovr
${{ steps.python-path.outputs.python-path }} -m gcovr -r .. \
--exclude '.*tests/.*' \
--exclude '.*tests/.*' \
--xml-pretty \
-o coverage.xml
- name: Upload coverage
# any except canceled or skipped
if: always() && (steps.test_report.outcome == 'success')
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
files: ./build/coverage.xml
flags: ${{ runner.os }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: Package Windows Debug Info
working-directory: build
run: |
# use .dbg file extension for binaries to avoid confusion with real packages
Get-ChildItem -File -Recurse | `
% { Rename-Item -Path $_.PSPath -NewName $_.Name.Replace(".exe",".dbg") }
# save the binaries with debug info
7z -r `
"-xr!CMakeFiles" `
"-xr!cpack_artifacts" `
a "../artifacts/sunshine-win32-debuginfo.7z" "*.dbg"
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: sunshine-windows
path: artifacts/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' }}
uses: ncipollo/release-action@v1
with:
name: ${{ needs.setup_release.outputs.release_name }}
tag: ${{ needs.setup_release.outputs.release_tag }}
commit: ${{ needs.setup_release.outputs.release_commit }}
artifacts: "*artifacts/*"
token: ${{ secrets.GH_BOT_TOKEN }}
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
release-winget:
name: Release to WinGet
needs: [setup_release, build_win]
if: |
(github.repository_owner == 'LizardByte' &&
needs.setup_release.outputs.create_release == 'true' &&
github.ref == 'refs/heads/master')
runs-on: ubuntu-latest
steps:
- name: Release to WinGet
uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: LizardByte.Sunshine
release-tag: ${{ needs.setup_release.outputs.release_tag }}
installers-regex: '\.exe$' # only .exe files
token: ${{ secrets.GH_BOT_TOKEN }}