mirror of
https://github.com/HayatoG/iss_pc.git
synced 2026-11-07 10:46:10 -10:00
331 lines
17 KiB
YAML
331 lines
17 KiB
YAML
# Builds and tests packages on PRs. Publishing is an explicit manual
|
|
# action: run this workflow on main with publish_release enabled to release accumulated PRs.
|
|
# No game or console file is ever built in or uploaded.
|
|
name: Build
|
|
|
|
on:
|
|
# Pull requests to main build both packages (artifacts only): the Release is left untouched.
|
|
pull_request:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
inputs:
|
|
publish_release:
|
|
description: 'Publicar release / Publish release (main only)'
|
|
type: boolean
|
|
required: true
|
|
default: false
|
|
beta:
|
|
description: 'Beta: pre-release da branch escolhida / pre-release of the chosen branch (not main)'
|
|
type: boolean
|
|
required: false
|
|
default: false
|
|
|
|
concurrency:
|
|
# Manual runs share a separate group: a new merge cannot cancel a publication.
|
|
group: ${{ github.event_name == 'workflow_dispatch' && 'manual-release' || format('build-{0}', github.ref) }}
|
|
cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
linux:
|
|
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && inputs.publish_release == true)
|
|
runs-on: ubuntu-24.04
|
|
defaults:
|
|
run:
|
|
working-directory: port
|
|
env:
|
|
CC: gcc-14
|
|
CXX: g++-14
|
|
PKG_CONFIG_PATH: /opt/tlgdeps/lib/pkgconfig:/opt/tlgdeps/lib64/pkgconfig:/opt/tlgdeps/lib/x86_64-linux-gnu/pkgconfig
|
|
CMAKE_PREFIX_PATH: /opt/tlgdeps
|
|
LD_LIBRARY_PATH: /opt/tlgdeps/lib:/opt/tlgdeps/lib64:/opt/tlgdeps/lib/x86_64-linux-gnu
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
- name: Release note tests
|
|
working-directory: .
|
|
run: python3 .github/scripts/test_release_notes.py
|
|
- name: System packages
|
|
run: |
|
|
sudo apt-get update -q
|
|
sudo apt-get install -y -q --no-install-recommends gcc-14 g++-14 cmake ninja-build pkg-config nasm \
|
|
curl git python3-venv python3-tk libvulkan-dev glslang-tools libboost-dev \
|
|
libxxhash-dev zlib1g-dev libx11-dev libxcb1-dev libxext-dev libxrandr-dev libxcursor-dev \
|
|
libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libwayland-dev wayland-protocols \
|
|
libdecor-0-dev libegl-dev libgl-dev libdrm-dev libgbm-dev libpulse-dev libasound2-dev \
|
|
libpipewire-0.3-dev libudev-dev libdbus-1-dev libusb-1.0-0-dev libfreetype-dev \
|
|
clang libssl-dev
|
|
- name: Cache built libraries
|
|
id: deps
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: /opt/tlgdeps
|
|
key: tlgdeps-ubuntu2404-${{ hashFiles('port/packaging/linux/build_deps.sh') }}
|
|
- name: Build libraries (SDL3, Zydis, fmt, FFmpeg)
|
|
if: steps.deps.outputs.cache-hit != 'true'
|
|
run: |
|
|
sudo mkdir -p /opt/tlgdeps && sudo chown "$USER" /opt/tlgdeps
|
|
bash packaging/linux/build_deps.sh
|
|
- name: Build
|
|
id: build
|
|
run: |
|
|
# Keep compilation progress visible while build.sh captures Ninja's full log.
|
|
(while sleep 30; do
|
|
echo "Build running: $(date -u +%H:%M:%S) UTC"
|
|
tail -n 2 out/gpu-build.log 2>/dev/null || true
|
|
done) &
|
|
progress_pid=$!
|
|
trap 'kill "$progress_pid" 2>/dev/null || true' EXIT
|
|
# TLG_RENDERER_V2=1: renderer v2 too (port/gpu_v2, out/tlg-probe-v2), shipped in the package.
|
|
TLG_RENDERER_V2=1 TLG_LTO=ON TLG_PGO=off bash build.sh
|
|
# The unit tests need no GPU, display or game file. Each test step runs even when an earlier
|
|
# one failed (all failures show in one run); any failure fails the job before Package.
|
|
- name: C tests
|
|
# build.sh's test list, reusing out/ from Build (same TLG_LTO/TLG_PGO: nothing is rebuilt).
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
|
|
run: TLG_LTO=ON TLG_PGO=off bash build.sh --test-only
|
|
- name: Python tests
|
|
# The venv is the one packaging/linux/package.sh reuses: the pinned PySide6 and iced-x86.
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
|
|
run: |
|
|
set -euo pipefail
|
|
source packaging/port.env
|
|
python3 -m venv out/pyenv
|
|
out/pyenv/bin/python -m pip install -q --disable-pip-version-check iced-x86==1.21.0 "$PORT_QT_PACKAGE"
|
|
QT_QPA_PLATFORM=offscreen out/pyenv/bin/python -m unittest discover -s tests
|
|
- name: GPU library tests
|
|
# Every *-test executable CMake defines in out/gpu for this platform (the Windows-only ones
|
|
# are not defined here); a test that needs a Vulkan driver prints SKIP without one. The link
|
|
# rule keeps out phony aliases of third-party targets. Each test runs in an empty directory.
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t tests < <(ninja -C out/gpu -t targets all |
|
|
grep -E '^[^/:]+-test: (C|CXX)_EXECUTABLE_LINKER' | cut -d: -f1 | sort)
|
|
(( ${#tests[@]} )) || { echo 'no GPU test targets in out/gpu'; exit 1; }
|
|
echo "GPU tests: ${tests[*]}"
|
|
ninja -C out/gpu "${tests[@]}"
|
|
gpu=$PWD/out/gpu
|
|
failed=()
|
|
for test in "${tests[@]}"; do
|
|
echo "::group::$test"
|
|
(cd "$(mktemp -d)" && timeout 600 "$gpu/$test") || failed+=("$test")
|
|
echo "::endgroup::"
|
|
done
|
|
(( ${#failed[@]} == 0 )) || { echo "::error::GPU tests failed: ${failed[*]}"; exit 1; }
|
|
- name: Package
|
|
run: bash packaging/linux/package.sh
|
|
- name: Smoke test (frozen Qt launcher)
|
|
# Opens the packaged launcher offscreen and renders a frame: a package whose launcher cannot
|
|
# start (missing Qt plugin, QML, font, translation) must not become a release.
|
|
run: |
|
|
set -euo pipefail
|
|
smoke=$(mktemp -d)
|
|
tar -C "$smoke" -xzf dist/infamous-linux-x86_64.tar.gz
|
|
out=$(QT_QPA_PLATFORM=offscreen timeout 120 "$smoke/infamous-linux-x86_64/inFAMOUS Second Son" --selftest 2>&1) || { echo "$out"; exit 1; }
|
|
echo "$out"
|
|
grep -qx 'selftest ok' <<<"$out"
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: infamous-linux-x86_64
|
|
path: port/dist/infamous-linux-x86_64.tar.gz
|
|
if-no-files-found: error
|
|
retention-days: 3
|
|
|
|
windows:
|
|
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && inputs.publish_release == true)
|
|
runs-on: windows-latest
|
|
defaults:
|
|
run:
|
|
shell: msys2 {0}
|
|
working-directory: port
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
- uses: actions/setup-python@v5
|
|
id: python
|
|
with:
|
|
python-version: '3.12'
|
|
- uses: msys2/setup-msys2@v2
|
|
with:
|
|
msystem: CLANG64
|
|
update: true
|
|
install: >-
|
|
git patch
|
|
mingw-w64-clang-x86_64-toolchain mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-ninja
|
|
mingw-w64-clang-x86_64-pkgconf mingw-w64-clang-x86_64-python
|
|
mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-vulkan-loader
|
|
mingw-w64-clang-x86_64-vulkan-memory-allocator mingw-w64-clang-x86_64-glslang
|
|
mingw-w64-clang-x86_64-sdl3 mingw-w64-clang-x86_64-fmt mingw-w64-clang-x86_64-boost
|
|
mingw-w64-clang-x86_64-robin-map mingw-w64-clang-x86_64-xxhash mingw-w64-clang-x86_64-ffmpeg
|
|
mingw-w64-clang-x86_64-zydis mingw-w64-clang-x86_64-spirv-tools
|
|
mingw-w64-clang-x86_64-spirv-headers mingw-w64-clang-x86_64-spirv-cross
|
|
mingw-w64-clang-x86_64-freetype
|
|
- name: Build
|
|
env:
|
|
MSYS2_ROOT: ${{ runner.temp }}/msys64
|
|
run: |
|
|
export MSYS2_ROOT=$(cygpath -u "$MSYS2_ROOT")
|
|
# Keep compilation progress visible while build.sh captures Ninja's full log.
|
|
(while sleep 30; do
|
|
echo "Build running: $(date -u +%H:%M:%S) UTC"
|
|
tail -n 2 out/gpu-build.log 2>/dev/null || true
|
|
done) &
|
|
progress_pid=$!
|
|
trap 'kill "$progress_pid" 2>/dev/null || true' EXIT
|
|
# TLG_RENDERER_V2=1: renderer v2 too (port/gpu_v2, out/tlg-probe-v2.exe), shipped in the package.
|
|
TLG_RENDERER_V2=1 TLG_LTO=ON bash build.sh
|
|
- name: Package
|
|
env:
|
|
MSYS2_ROOT: ${{ runner.temp }}/msys64
|
|
WINPYTHON_WIN: ${{ steps.python.outputs.python-path }}
|
|
run: |
|
|
export MSYS2_ROOT=$(cygpath -u "$MSYS2_ROOT")
|
|
export WINPYTHON=$(cygpath -u "$WINPYTHON_WIN")
|
|
bash packaging/windows/package.sh
|
|
- name: Smoke test (frozen Qt launcher)
|
|
# Unzips the package and runs the frozen launcher with --selftest (Qt offscreen platform).
|
|
# The windowed exe has no console, so it writes its result to a file that is checked here.
|
|
shell: pwsh
|
|
working-directory: port
|
|
run: |
|
|
$smoke = Join-Path $env:RUNNER_TEMP 'smoke'
|
|
Remove-Item -Recurse -Force $smoke -ErrorAction SilentlyContinue
|
|
Expand-Archive -Path dist/infamous-windows-x86_64.zip -DestinationPath $smoke
|
|
$exe = Join-Path $smoke 'infamous-windows-x86_64/inFAMOUS Second Son.exe'
|
|
$outFile = Join-Path $env:RUNNER_TEMP 'selftest.txt'
|
|
Remove-Item $outFile -ErrorAction SilentlyContinue
|
|
$env:QT_QPA_PLATFORM = 'offscreen'
|
|
$env:ISS_SELFTEST_OUT = $outFile
|
|
$p = Start-Process -FilePath $exe -ArgumentList '--selftest' -PassThru
|
|
if (-not $p.WaitForExit(180000)) { $p.Kill(); Write-Error 'selftest timed out'; exit 1 }
|
|
if (Test-Path $outFile) { Get-Content $outFile }
|
|
if ($p.ExitCode -ne 0 -or -not (Test-Path $outFile) -or -not ((Get-Content $outFile -Raw) -match 'selftest ok')) {
|
|
Write-Error "selftest failed (exit code $($p.ExitCode))"
|
|
exit 1
|
|
}
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: infamous-windows-x86_64
|
|
path: port/dist/infamous-windows-x86_64.zip
|
|
if-no-files-found: error
|
|
retention-days: 3
|
|
|
|
beta:
|
|
# A manual run with "beta" on a branch other than main: beta.yml builds, tests and publishes a
|
|
# pre-release of that branch (never Latest; posted only to the Discord beta channels, never
|
|
# #chat-geral). The jobs above stay skipped.
|
|
if: github.event_name == 'workflow_dispatch' && inputs.beta == true && github.ref != 'refs/heads/main'
|
|
permissions:
|
|
contents: write
|
|
pull-requests: read
|
|
uses: ./.github/workflows/beta.yml
|
|
with:
|
|
branch: ${{ github.ref_name }}
|
|
# The beta channels' Discord webhooks (DISCORD_BETA_WEBHOOK, DISCORD_BETA_CHAT_WEBHOOK).
|
|
secrets: inherit
|
|
|
|
release:
|
|
needs: [linux, windows]
|
|
# Approval, merge and tag pushes never publish. Both platform jobs must pass first.
|
|
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && inputs.publish_release == true
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: write
|
|
pull-requests: read
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
GH_REPO: ${{ github.repository }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
sparse-checkout: |
|
|
docs/ARQUIVOS_NECESSARIOS.md
|
|
.github/scripts/release_notes.sh
|
|
sparse-checkout-cone-mode: false
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
path: dist
|
|
merge-multiple: true
|
|
- name: Publish
|
|
id: publish
|
|
run: |
|
|
set -euo pipefail
|
|
ls -la dist
|
|
test -f dist/infamous-linux-x86_64.tar.gz && test -f dist/infamous-windows-x86_64.zip
|
|
short=${GITHUB_SHA::7}
|
|
# Put accumulated changes first, before package and setup instructions.
|
|
bash .github/scripts/release_notes.sh "$GITHUB_SHA" > notes.md
|
|
cat >> notes.md <<NOTES
|
|
Publicação manual do commit ${short}. **Nenhum arquivo do jogo incluído**: veja o README-player.md dentro do pacote para o que copiar do seu PS4.
|
|
Manual release of commit ${short}. **No game files included**: see README-player.md inside the package for what to copy from your PS4.
|
|
|
|
☕ Apoie o desenvolvimento / Support development: [Buy me a coffee](https://buymeacoffee.com/hayatog)
|
|
|
|
- Linux x86-64 (glibc 2.39+): \`infamous-linux-x86_64.tar.gz\`
|
|
- Windows 10/11 64-bit: \`infamous-windows-x86_64.zip\`
|
|
|
|
**Sensor de movimento e touchpad** (grafite, absorver poderes, portas): no DualShock 4/DualSense funcionam direto. Em outros controles, um toque em **L3+R3** liga/desliga o modo sensor (ou Share no Xbox Series): ele é a lata de spray do grafite: o controle fica de lado, X/A sacode, R2 pinta e o **analógico esquerdo mira** o cursor (para os lados e para cima/baixo; ele fica onde você soltar). **View/Select** é o clique do touchpad (segurar para absorver fumaça, neon...), e **View/Select + analógico direito** desliza. Teclado: T/G viram de lado (as setas miram enquanto seguram), Y sacode, F pinta (R2), Tab/Backspace clicam, Tab + setas deslizam, Tab + Backspace apertam as duas pontas (View/Select + R1 no controle: levantar o carro de cima do Reggie). A zona morta dos analógicos fica no launcher.
|
|
|
|
**Motion sensor and touchpad** (graffiti, absorbing powers, doors): on a DualShock 4/DualSense they work as is. On other controllers, one tap on **L3+R3** toggles sensor mode (or Share on an Xbox Series): it is the graffiti's spray can: the controller is held sideways, cross/A shakes, R2 sprays and the **left stick aims** the cursor (left/right and up/down; it stays where you let go). **View/Select** is the touchpad click (hold it to absorb smoke, neon...), and **View/Select + right stick** swipes. Keyboard: T/G turn it sideways (the arrow keys aim while held), Y shakes, F sprays (R2), Tab/Backspace click, Tab + arrow keys swipe, Tab + Backspace press both ends (View/Select + R1 on a controller: lifting the car off Reggie). The stick dead zone is in the launcher.
|
|
|
|
NOTES
|
|
# The list of game files the player needs (docs/ARQUIVOS_NECESSARIOS.md), before the download.
|
|
sed '1,/^\[Português\]/d' docs/ARQUIVOS_NECESSARIOS.md >> notes.md
|
|
tag="v$(date -u +%Y.%m.%d)-${short}"
|
|
# A re-run of the same commit finds its release already published: keep it.
|
|
if gh release view "$tag" --json isDraft --jq .isDraft 2>/dev/null | grep -qx false; then
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"; exit 0
|
|
fi
|
|
# SHA256SUMS: the launcher's updater checks the downloaded package against it.
|
|
(cd dist && sha256sum infamous-linux-x86_64.tar.gz infamous-windows-x86_64.zip > SHA256SUMS)
|
|
# Upload into a draft first, so a failed upload never leaves a half-published release.
|
|
# Releases are kept forever as version history; nothing here deletes one.
|
|
gh release create "$tag" dist/* --draft --target "$GITHUB_SHA" \
|
|
--title "$tag ($(date -u +%Y-%m-%d) · ${short})" --notes-file notes.md
|
|
n=$(gh release view "$tag" --json assets --jq '.assets | length')
|
|
[[ $n -ge 3 ]] || { echo "draft release has $n assets"; exit 1; }
|
|
for try in 1 2 3; do
|
|
gh release edit "$tag" --draft=false --latest && break
|
|
sleep 10
|
|
done
|
|
[[ $(gh release view "$tag" --json isDraft --jq .isDraft) == false ]]
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "published=true" >> "$GITHUB_OUTPUT"
|
|
- name: Notify Discord
|
|
# Posts the new release to #chat-geral. A Discord failure never fails the build.
|
|
if: steps.publish.outputs.published == 'true'
|
|
continue-on-error: true
|
|
env:
|
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
|
|
GAME: InFamous Second Son
|
|
run: |
|
|
set -euo pipefail
|
|
[[ -n "${DISCORD_WEBHOOK:-}" ]] || { echo "DISCORD_RELEASE_WEBHOOK not set"; exit 0; }
|
|
tag=${{ steps.publish.outputs.tag }}; color=5763719
|
|
short=${GITHUB_SHA::7}
|
|
url="$GITHUB_SERVER_URL/$GH_REPO/releases/tag/$tag"
|
|
downloads=$(gh release view "$tag" --json assets \
|
|
--jq '[.assets[] | select(.name != "SHA256SUMS") | "• [\(.name)](\(.url))"] | join("\n")')
|
|
# One card per release: only the "## Novidades" section of the release notes (the full
|
|
# notes are one click away). Without that section, the commit message stands in.
|
|
news=$(gh release view "$tag" --json body --jq .body | tr -d '\r' |
|
|
awk '/^## Novidades/ { on = 1; next } /^## / { on = 0 } on' |
|
|
sed -e '/./,$!d' | sed -e ':a' -e '/^\n*$/{$d;N;ba' -e '}')
|
|
[[ -n $news ]] || news="- $(git log -1 --format=%s "$GITHUB_SHA" 2>/dev/null || echo "Build $short")"
|
|
jq -n \
|
|
--arg title "🎮 $GAME: nova versão ($tag)" --arg url "$url" \
|
|
--arg news "$news" --arg dl "$downloads" --arg commit "Commit $short" \
|
|
--argjson color "$color" '
|
|
(if ($news | length) > 3500
|
|
then ($news[:3500] | sub("\n[^\n]*$"; "")) + "\n… [notas completas](\($url))"
|
|
else $news end) as $d
|
|
| {username: "Novas versões", embeds: [{title: $title, url: $url, description: $d, color: $color,
|
|
fields: [{name: "Downloads", value: $dl}], footer: {text: $commit}}]}' |
|
|
curl -fsS -H 'Content-Type: application/json' -d @- "$DISCORD_WEBHOOK"
|
|
# Artifacts expire through retention-days; keep run history and PR checks intact.
|